I’ve updated my previous post “The many flavors of HttpClient” with current information on everything you need to know about HttpClient on Xamarin.
When using Xamarin, you can use the standard .NET
HttpClient. By default, HttpClient is Mono’s complete reimplementation of the entire HTTP stack. It is sufficient for many use cases but there are other alternatives out there that can be defined by selecting an alternative
HttpClientHandler. For my Evolve talk, I put together an overview of the different HttpClientHandlers you can use:
CFNetworkHandler (iOS 6+) and the new
NSUrlSessionHandler (iOS 7+, starting with Xamarin.iOS 9.8) are the handlers that utilize Apple’s native APIs instead of the Mono implementation. You can define which handler the
HttpClient default constructor will use either in the IDE or by providing an argument to
For Android, there is now
AndroidClientHandler (starting with Xamarin.Android 6.1). There is no IDE option for defining the default handler yet but you can define it using the
@(AndroidEnvironment) build action on a text file in your Android project to define an environment variable
XA_HTTP_CLIENT_HANDLER_TYPE to the value
Alternatively, you can use ModernHttpClient by handing a
NativeMessageHandler to the HttpClient constructor which will also use native implementations for making HTTP calls.
The default Mono implementation does not support the newest (and most secure) TLS standard 1.2 while the native handlers do. To use TLS 1.2 with the Mono implementation, Xamarin.iOS 9.8 introduced the option to swap the TLS implementation with P/Invoke calls into the Apple’s TLS implementation. This can be selected either in the IDE or by adding the
--tls-provider=appletls option to
For Android, there is no such option but it is expected that
BoringSSL support will be added soon.
Here’s the summary slide I showed in my talk:
Xamarin have actually gone through the trouble of reimplementing the TLS code to support TLS 1.1 and 1.2. However, it is expected that it will be abandoned because of security considerations in favor of the native platform implementations, just as Microsoft has done for Windows.
Here’s an update on the current state of
AndroidClientHandleryour Android project’s properties page, just as you already could for iOS.
BoringSSLinto their codebase. For Android, this option is also selectable in your project’s properties page.
BoringSSLalso brings TLS 1.2 to the Unix/Linux implementations of Mono.
ServicePointManager. Thomas Bandt wrote an excellent blog post on how to get certificate pinning working with ModernHttpClient and even
And here’s the updated matrix:
Communicating securely between a mobile app and a the corresponding backend is not a trivial task. Sure, nowadays we can write https and almost be certain our app is actually having encrypted communication with the right backend. However, just recently, I decided to do a communications check of apps on my iPhone using Fiddler as a proxy and was surprised to find that I could do a man-in-the-middle attack for an app I use regularly without the app noticing this. Apparently, the developers had opted to disable certificate validation (perhaps so the app would work with a developer backend that doesn’t have a pricey SSL server certificate installed) and forgot to turn it on again before publishing the app to the store.
However, there is an even better way to solve that problem that doesn’t involve buying an SSL server certificate. It’s called certificate pinning. Instead of relying on the operating system to check the validity of the presented server certificate by looking at its list of root certification authorities (which may contain entries the user is not aware of, see Superfish) developers can instruct their https calls to only accept a specific server certificate or, better yet, only certificates issued by a specific certification authority. This is not only much safer, it also avoids the costs of buying SSL server certificates.
So there we are, we have a method to ensure our app is talking to the right backend. The trickier part, though, is ensuring that whoever is making the call to our backend is actually who we think they are (i.e., our own app).
A simple approach to this problem would be to include an SSL client certificate in all requests to the backend, using a certificate whose private key is included as part of the app bundle. The problem with this is that it’s just not possible to hide the certificate well enough in our bundle to make it impossible to extract that certificate and its private key through reverse engineering. And since all clients would be using the same certificate, having that certificate compromised means we cannot tell if it’s acutally our app that is calling the backend.
The solution to this problem is to issue individual SSL client certificates to each device that is accessing the backend.
The vendors of Mobile Device Managament (MDM) software have great solutions that do exactly that. The problem is that these solutions can only be applied to devices that are in full control of the MDM solution. That’s great for internal apps on company devices but doesn’t help at all for apps you’re distributing to others.
Here is my proposal: App store operators should include a method to create an unique SSL client certificate upon installation of the app that is signed either using a certificate (public and private key) the app creator uploads into the app store or a certificate created by the app store vendor. This would make it very easy to check on the server side if a request is coming from an app that was actually distributed through the app store (and paid for, in the case of non-free apps) by using the signing certificate’s public key.
Such a feature could also be included in cloud backends like Azure Mobile Services where one could limit requests only to genuine apps and provide the corresponding functionality the client libraries accessing the backend.
All in all, this approach would greatly increase app communication security without much effort for the app developer. Now, how to convince the app store operators?