Xamarin - HttpClient, establish connection between iOS and server - xamarin.forms

I'm using HTTPClient in Xamarin to call my server but sometimes the request takes a lot of time on IOS so I did check packet trace with wireshark and saw that the server doesn't reply. The Iphone sent a SYN but no SYN ACK from the server so when I using HTTPClient.PostAsync() and after X seconds, an exception is throw The request timed out. This issue appears sometimes but not all the time and on Android, HttpClient works perfectly.
private static HttpClient client = new HttpClient();
try
{
var response = await client.PostAsync(url, json);
.....
}
catch (Exception ex)
{
//exception
}
The HttpClient Implementation is on NSUrlSession.

Welcome to SO !
Any connection made with NSUrlConnection, CFUrl or NSUrlSession will use ATS by default in apps built for iOS 9 and OS X 10.11 (El Capitan).
Since ATS is enabled by default in apps built for iOS 9 and OS X 10.11 (El Capitan), all connections using NSUrlConnection, CFUrl or NSUrlSession will be subject to ATS security requirements. If your connections do not meet these requirement, they will fail with an exception.
ATS will enforce the following requirements for all internet connections:
All connection ciphers must be using forward secrecy. See the list of accepted ciphers below.
The Transport Layer Security (TLS) protocol must be version 1.2 or greater.
At least a SHA256 fingerprint with either a 2048 bit or greater RSA key, or a 256 bit or greater Elliptic-Curve (ECC) key must be used for all certificates.
Again, since ATS is enabled by default in iOS 9, any attempt to make a connection that doesn't meet these requirements will result in an exception being thrown.
In addition , if using http in xamarin iOS , you can add follow content into info.plist :
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key><false/>
</dict>
Reference : App Transport Security in Xamarin.iOS

Related

DocumentDB: using TCP connection with client lib > 1.9.0

With Microsoft.Azure.DocumentDB 1.9.0 the ConnectionProtocol variable in the ConnectionPolicy has been made obsolete with the comment:
"This property is deprecated. Please use ConnectionMode to choose communication protocol in conjution with connection endpoint mode."
We still set it to Tcp, and we set ConnectionMode to Direct. However, when doing a Fiddler capture of our app I can see the requests going to DocumentDb over HTTPS.
How do I force the lib to use the Tcp connection? Do I have to change the endpoint string? Ours is currently of the form:
https://mydocumentdb.documents.azure.com:443
as that's what Azure tells us to use. I'm really not clear what the comment means by "connection endpoint mode".
EDIT: By request, here's my connection code:
DocumentDbConnection ConnectionData = new DocumentDbConnection();
ConnectionPolicy ClientConnectionPolicy = ConnectionPolicy.Default;
ClientConnectionPolicy.ConnectionMode = ConnectionMode.Direct;
ClientConnectionPolicy.ConnectionProtocol = Protocol.Tcp;
ConnectionData.DbClient = new DocumentClient( new Uri( DbEndpoint ), AccountKey, ClientConnectionPolicy );
// do initial connection upfront to avoid first-query latency
await ConnectionData.DbClient.OpenAsync();
DatabaseAccount DbAccount = await ConnectionData.DbClient.GetDatabaseAccountAsync();
Direct TCP mode is only supported for any requests for server resources(like Documents). Requests for master resources(like document collection) will still go through the Gateway.
Can you elaborate what kind of requests you are seeing in fiddler? Note that the client initialization related requests will also go through gateway and any subsequent requests for server resources will be directed using TCP.
Are you using partitioned collections feature?
Note that we brought back the ConnectionProtocol in .NET SDK 1.9.2(which was marked as Obsolete earlier). If you were setting the Protocol to TCP and Mode to Direct even earlier it should work as expected. No need to change the endpoint string.
Regards,
Rajesh

Why does calling an ASP.NET ASHX handler from VBScript work but gets a "could not create SSL/TLS secure channel" error in .NET?

Recently, one of our ASP.NET ASHX handlers that makes a call to another ASHX handler on another server started to fail with the following error: "Unhandled Exception: System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel." Installing the certificate for the other server did not help (in any case, the other server is public-facing and has a cert signed by a CA).
I wrote a small C# program to test if I could connect to the other server from the command line:
using System.Net;
public class Test
{
const string theUrl = "https://www.example.com/Handler.ashx?ID=123";
public static void Main(string[] args)
{
var req = WebRequest.Create(theUrl);
var resp = req.GetResponse();
}
}
This, too, fails with a System.Net.WebException: The request was aborted: Could not create SSL/TLS secure channel. However, if I make the call to the handler from a VBScript file:
Const theUrl = "https://www.example.com/Handler.ashx?ID=123"
Dim oXmlHttp
Set oXmlHttp = WScript.CreateObject("Microsoft.XMLHTTP")
With oXmlHttp
.Open "GET", theUrl, False
.Send
WScript.Echo CStr(.Status)
End With
Set oXmlHttp = Nothing
it works; the script returns a status of 200!
I checked the .NET machine.config file as I encountered a similar issue in the past where requests sent from unmanaged code worked but not from .NET because the proxy settings were different, but this is not the case here. Why should a request from VBScript work but fail from .NET?
EDIT: Enabling tracing reveals a similar error to the one reported in this question:
System.Net Information: 0 : [28468] InitializeSecurityContext(credential = System.Net.SafeFreeCredential_SECURITY, context = 1ad5f0:29f3620, targetName = www.example.com, inFlags = ReplayDetect, SequenceDetect, Confidentiality, AllocateMemory, InitManualCredValidation)
System.Net Information: 0 : [28468] InitializeSecurityContext(In-Buffers count=2, Out-Buffer length=0, returned code=AlgorithmMismatch).
System.Net.Sockets Verbose: 0 : [28468] Socket#3741682::Dispose()
System.Net Error: 0 : [28468] Exception in the HttpWebRequest#2383799:: - The request was aborted: Could not create SSL/TLS secure channel.
System.Net Error: 0 : [28468] Exception in the HttpWebRequest#2383799::GetResponse - The request was aborted: Could not create SSL/TLS secure channel.
"Algorithm mismatch" is a bit vague, especially since TLS errors are well defined. No matter.
Run ssl-enum-ciphers (perl) or nmap's equivalent against the server to see what SSL/TLS versions and ciphers it supports, and prefers. In pinch you could try MS wfetch to do something similar, but it has quite limited protocol and cipher support.
You can do the equivalent for the client using openssl as a server (key+cert required):
openssl s_server -quiet -accept 4443 -key server.key -cert server.crt
optionally mix in -no_xxx or -xxx where xxx is one of ssl2, ssl3, tls1 for variety.
(Browser friendly, but less easy to code/automate is https://www.ssllabs.com/ssltest/viewMyClient.html or see here for more.)
The way the protocol/cipher agreement works is that the client sends (ClientHello) an SSL/TLS version, a list of ciphers (and extensions), then server chooses the protocol version, and a cipher in common (intersecting set) and replies (ServerHello). The (rough) method for choosing is:
use the highest SSL/TLS version supported by the client, or give up (possible handshake failure)
prefer the first common cipher in the client list, i.e. assume it's ordered by preference
-or- prefer the first common cipher in the server list [1]
-or- give up with (no common cipher)
[1] this allows the operator to configure the server prefer ciphers based on other than "strength" (symmetric key-size), e.g. to force 128-bit RC4 over AES-256 while supporting both, as was the style a year or two back.
The default cipher order is usually by descending "strength" (symmetric cipher key size). An SSL/TLS protocol version sets out an expected set of ciphers, but supporting the same cipher (e.g. AES-128) isn't enough.
It can be the case that the client won't talk TLS, and the server won't talk SSL, e.g. https://serverfault.com/questions/208542/what-might-cause-https-failure-when-not-specifying-ssl-protocol
This should cause a protocol or handshake error though.
Since forcing the protocol via SecurityProtocolType.Ssl3 (another case here), it looks like the client is proposing something the server doesn't like -- if you have confirmed both sides support TLS then it might be SNI tripping you up, and falling back to SSL3 side-steps that.
In the unlikely event that the client side is defaulting to SSlv2, the server is quite right to reject it ;-)
We found a workaround but it's not particularly elegant. The problem started to occur when the server to which we are connecting was replaced with a load-balanced configuration. If I edit the hosts file on the client machine to talk to the server directly rather than go through the load-balancer, it works.
In addition, I verified that the code changes in this answer also work. It would still be nice to know the differences are between the managed and unmanaged implementations of SSL/TLS...

HttpWebRequest AllowReadStreamBuffering property not honored on cellular network?

I'm writing an app which uses persistent connections over http - that is, the web server never "finishes" writing to the response stream, and the client app reads data from the response stream as it comes in.
I wrote some .NET 3.5 desktop/winforms apps to confirm that the server & client code works, and then wrote a windows phone app to do the same thing. The only difference between the desktop/phone code was that I set the AllowReadStreamBuffering property to false on the phone.
The phone app worked last night, but today it does not work - when attempting to read the response stream, it hangs until the connection is closed from the server side - which means that the AllowReadStreamBuffering setting is not being honored by HttpWebRequest.
The difference between last night and now is that last night, I was on wifi, whereas today i'm connected over cellular.
My hypothesis is that on the phone, HttpWebRequest only honors AllowReadStreamBuffering = false when the connection is wifi (and perhaps Ethernet), but that it ignores it and buffers when using the cellular network.
So is it true that HttpWebRequest forces read stream buffering when connected over cellular? I haven't been able to find any documentation that confirms this behavior, so I'm wondering if anybody else has experienced this. I'll be able to test this more thoroughly later, but for now I figured i'd ask the question.
UPDATE 5-11-12
Tested and answered my own question (see below)
AllowReadStreamBuffering = false is honored on cellular connections; otherwise (for example) audio streaming apps wouldn't function properly.
I verified that my WP7 app would not initially read the response stream unbuffered when connected via cellular - it only does so when on ethernet or wifi.
So I modified my server httphandler to write an initial chunk of data (8k) to the response stream, at the beginning of the connection. Doing this made the app read the response stream immediately on cellular, just like it did when it was on wifi. After ignoring the initial blast of data, the app processed the individual bytes just fine, and in real-time.
The only conclusion that I can think of is that when connected over cellular, HttpWebRequest initially requires a small amount of data to be buffered before allowing the stream to be read unbuffered.

Explanation for CONNECT observations using Fiddler for url https://www.fiddler2.com/fiddler2/version.asp

I'm using IE9 beta and Fiddler to understand the https session negotiation taking place for the above url (chosen for no paritcular reason other than it's secured).
Some observations made me curious.. does anyone understand what's happening here?
1. When I connect with Fiddler setting: HTTPS decrypt OFF, I see this sequence
5 CONNECTs to fiddler2.com with nothing but headers showing
a) Curious, why more than one?
1 CONNECT to beta.urs.microsoft.com
b) Does this have something to do with asking MS which cert it recognises? I thought this data is supposed to be kept locally? Maybe that only happened because I'm using a beta of IE9?
4 CONNECTs to fiddler2.com with the same SessionID but different Random and the list of ciphers available on the client.
1 CONNECT to beta.urs.microsoft.com with similar content to above 4
c) Why the multiple CONNECTs here with different Random?
2. When I connect with Fiddler setting: HTTPS decrypt ON, I see this sequence
5 CONNECTs to fiddler2.com with nothing but headers in the request only and the response shows a certificate and the chosen cipher. Same in all 5.
a) same question
1 GET with the page contents
d) what happened to the extra CONNECTs this time?
I'm trying to relate what I see here to the negotiation between client and server as it's documented here.
Transport Layer Security
Tyia,
Mick.
You didn't mention what browser you're using and what ciphers you have enabled in that browser.
Sometimes, you'll see multiple CONNECT handshakes because the server immediately closes the connection (ungracefully stating that they don't support the requested protocol version) and the client will retry (fallback) to an older protocol version. You definitely see this happen a lot if you enable TLSv1.1 and TLSv1.2 in IE, for instance.
You also may see multiple CONNECTs if the client aborts a connection and then attempts to open a new one.
urs.microsoft.com and beta.urs.microsoft.com are used for the SmartScreen site-reputation feature.

HTTP Error: 400 when sending msmq message over http

I am developing a solution which will utilize msmq to transmit data between two machines. Due to the seperation of said machines, we need to use HTTP transport for the messages.
In my test environment I am using a Windows 7 x64 development machine, which is attempting to send messages using a homebrew app to any of several test machines I have control over.
All machines are either windows server 2003 or server 2008 with msmq and msmq http support installed.
For any test destination, I can use the following queue path name with success:
FORMATNAME:DIRECT=TCP:[machine_name_or_ip]\private$\test_queue
But for any test destination, the following always fails
FORMATNAME:DIRECT=$/test_queue
I have used all permutations of machine names/ips available. I have created mappings using the method described at this blog post. All result in the same HTTP Error: 400.
The following is the code used to send messages:
MessageQueue mq = new MessageQueue(queuepath);
System.Messaging.Message msg = new System.Messaging.Message
{
Priority = MessagePriority.Normal,
Formatter = new XmlMessageFormatter(),
Label = "test"
};
msg.Body = txtMessageBody.Text;
msg.UseDeadLetterQueue = true;
msg.UseJournalQueue = true;
msg.AcknowledgeType = AcknowledgeTypes.FullReachQueue | AcknowledgeTypes.FullReceive;
msg.AdministrationQueue = new MessageQueue(#".\private$\Ack");
if (SendTransactional)
mq.Send(msg, MessageQueueTransactionType.Single);
else
mq.Send(msg);
Additional Information: in the IIS logs on the destination machines I can see each message I send being recorded as a POST with a status code of 200.
I am open to any suggestions.
The problem can be caused by the IP address of the destination server having been NAT'ed through a Firewall.
In this case the IIS server receives the message okay and passes it on to MSMQ. MSMQ then reads the message and sees the destination of the message as being something different than the known IP addresses of the server. At this point MSMQ rejects the message and IIS returns a HTTP status 400.
Fortunately the solution is fairly straightforward. Look in %windir%\System32\msmq\mapping. This folder can contain a bunch of xml files (often sample files are provided) that each contain mappings between one address and another. The name of the file can be anything you like, here is an example of the xml formatted contents:
<redirections xmlns="msmq-queue-redirections.xml">
<redirection>
<from>http://external_host/msmq/external_queue</from>
<to>http://internal_host/msmq/internal_queue</to>
</redirection>
</redirections>
The MSMQ service then needs restarting to pickup the new configuration, for instance from the command line:
net stop msmq
net start msmq
References:
http://blogs.msdn.com/b/johnbreakwell/archive/2008/01/29/unable-to-send-msmq-3-0-http-messages.aspx
http://msdn.microsoft.com/en-us/library/ms701477(v=vs.85).aspx
Maybe you have to encode the $ as %24.

Resources