Category Archives: Security

The best way to know all the network communication your app is doing is to inspect the network traffic to and from your phone while your app is running. My favorite tool for doing this is Fiddler by Progress Telerik.

About Fiddler

Fiddler is a free Web Debugging Proxy for Windows. Its intended purpose is to allow web developers to inspect their browsers’ traffic. It was released in 2003 when browsers did not yet provide the nice debugging tools that browsers have nowadays. When launching Fiddler, it will start a proxy server and automatically register itself as the system HTTP proxy server for all browsers that use the system’s settings (e.g., IE, Edge, Chrome, Safari, Opera, etc.) and for Firefox. If you then call a web site from your browser you can see, in detail, all the traffic the browser is requesting from any server and all the responses.

Using Fiddler with mobile apps

But Fiddler will also let you capture the traffic from any app, even if it’s not on the same machine, if you tell that app to send its requests through the proxy server Fiddler provides. We’ll look at how to do this for a mobile app. To do this, it is usually a good idea to first turn off the capturing of your browser and operating system requests by disabling File → Capture Traffic (F12) so you only see the requests from your app.

The next thing to do is to tell Fiddler to open a port to allow apps from other hosts to connect to it. This is done by checking Allow remote computers to connect in the Connections tab under Tools → Options.

Now head over to your mobile phone. The phone will have to be inside the same wifi and the wifi will need to allow hosts to be able to communicate with each other. Such wifi networks are typically found at home or inside companies but not in public places. In the phone’s preferences, set your wifi’s proxy server to be the IP address of your PC and the TCP port that was set inside the Connections tab in Fiddler (the default is 8888).

On iOS, you’ll find this setting under Settings → Wifi, tap the ⓘ next to your wifi, then under HTTP Proxy → Configure Proxy, set to Manual, the set the Server to the IP address of your PC and the Port to the TCP port (typically 8888).

Inspecting app traffic

Lets launch one of my favorite apps, FlightRadar24, and look at the communication.

Looking at the communication, we see a lot of requests being sent out to multiple servers. But upon inspecting these requests, we notice we can see the contents of none of them. This is because the FlightRadar24 app is using HTTPS (which it should) for all of its requests.

Inspecting HTTPS traffic

The solution to this is to instruct Fiddler to Decrypt HTTPS traffic in the HTTPS tab of the settings.

What this does is essentially a TLS man-in-the-middle attack (for more details, see the previous blog post in this series on certificate pinning).

Looking at the communication, we notice that we see a lot of requests but their size is always 0. We also notice the app is not showing any flight movement information.

The reason for this is that, in order to do intercept the traffic and inspect the contents, Fiddler doesn’t forward the request to the server directly but instead acts as a web server towards our app. To do this, it creates a server certificate, issued by its own certificate authority. Since this certificate authority is not one that is trusted by the operating system, the HTTPS request inside the app fails. The FlightRadar24 app chooses not to show an error message when this happens so to the end user the result is that no flights show up.

Installing the FiddlerRoot certificate

What we can now do is get the operating system to trust the certificate issued by Fiddler. I’ll show how to do this for iOS.

This page provides the Fiddler root certificate. Installing a new root certificate is something that should be done with care. For this reason, the operating system will ask you to confirm multiple security prompts.

Tap FiddlerRoot certificate.

Tap Allow.

Tap Install to install the certificate DO_NOT_TRUST_FiddlerRoot.

Tap Install again.

Tap Install again.

Tap Done.

Open the Settings app and go to General → About → Certificate Trust Settings.

Activate the switch next to the DO_NOT_TRUST_FiddlerRoot certificate to enable the certificate. Make sure to turn this switch back off after you’ve finished inspecting your app’s traffic.

Confirm the installation by tapping Continue.

You’re done! The iPhone will now trust HTTPS requests that have intercepted by Fiddler.

Let’s have a look at the FlightRadar24 app again.

Suddenly, the app is working again and we can inspect all the traffic! Now you can dig into each request and see the communication the app is having with each server. Using Fiddler’s AutoResponder, you could also manipulate the data the app is receiving.

The reason this works is that the app is relying on the operating system to check the validity of certificates for HTTPS communication. If the app had been using certificate pinning, we would not be able to inspect the traffic at all using Fiddler.

Xamarin caveats

One more note for Xamarin developers: Requests from your app to a backend are typically sent using HttpClient. There are multiple implementations of the HttpClientHandler that HttpClient can use and not all of them honor the HTTP proxy settings of the operating system. I wrote another blog post on the different types of handlers. If none of your app’s communication is showing up in Fiddler although the app is working, you will have to set the HTTP proxy server manually in your code.

HTTPS is on the rise. This is a good thing. HTTPS ensures your network communication is encrypted in both directions, protecting your app’s users. If you write the code

you are basically doing the same as a user entering the URL into the browser’s address bar would do. The user agent does a handshake with the host you specified, retrieves its certificate and checks the validity of that certificate according to a few criteria, e.g., host name, expiration date, revokation, and trust chain. Let’s have a look at a certificate, in this case the one for www.microsoft.com:

You can see details such as the expiration date or the host names the certificate is valid for. You can also see the certificate chain. This certificate was issued by the certificate authority “Microsoft IT TLS CA 4”. And its certificate was issued by “Baltimore CyberTrust Root”. Baltimore CyberTrust Root is in the list of trusted root certificates of most operating systems and that is why I can connect to https://www.microsoft.com/ without getting an error message.

This root certificate list is unfortunately the weakest link in the entire HTTPS story. Most users don’t check which root certificates are installed on their machine. There have been cases where computer vendors added their own certificate to the root certificates list. And there are also numerous companies that install the company’s root certificate onto each employee’s device so they can monitor all traffic by doing a man-in-the-middle attack.

For the browser story, this is currently the only way to make sure your browser can connect to all HTTPS servers on the internet, even those it has never contacted. But for a connection from a mobile app to its backend, you usually know exactly which server you’re connecting to. From a security perspective, it is a good idea to take advantage of this.

Check which server you’re connecting to

The most effective thing you can do is to get the root certificate list out of the picture. If you control the server and the certificate on the server, you can check if the certificate is the exact certificate you are expecting. You can do this by comparing if certificate’s public key is the one you are expecting. Here’s how to do that with .NET:

This code replaces the default certificate validation with custom code. This code compares the public key of the server’s certificate with the expected pubic key of the server. This public key corresponds with the private key that is installed on the server. Since it is not possible to derive the private key from a public key, this means that we can guarantee we’re talking to that one server and not any server our operating system happens to trust.

This code has a couple of limitations you should be aware of:

It only works for this one server. If you have multiple servers you’re connecting to with different public keys, you’ll have to differentiate her.

This code does not account for changes to the server certificate. In the case of connecting to a server you don’t control yourself, the certificate could be changed at any point which we require an update of the app for it to work again.

You could check other criteria, e.g., the certificate’s expiration date.

An alternative you can think about is rolling your own certificate authority and pinning not the certificate itself but the certificate authority. Even though a browser would not trust such a certificate from an unknown certificate authority, a mobile app would work just fine.

Only allow up-to-date TLS

What is commonly referred to as SSL (Secure Sockets Layer) was actually renamed to TLS (Transport Layer Security) in 1999. TLS 1.2 is the current version and TLS 1.3 is expected to be finalized soon. All older version, including SSL 2, SSL3, TLS 1.0, and TLS 1.1 should not be considered sufficiently secure anymore at this point. At this time, TLS 1.2 should be used for all communication.

When using default settings, both the client and server will allow downgrading the connection to an older standard as part of the initial handshake. This is to allow new clients to connect to old servers and to allow old clients connect to new servers. But since we’re controlling both client and server, there is no reason to allow downgrades to the not sufficiently secure TLS version 1.1 or lower. The solution is to force both the client and the server to only allow TLS 1.2 connections. With HttpClient in .NET, this is done like this:

Xamarin-specific issues

Xamarin developers will have to be aware that there are different implementations of HttpClient available and not all support TLS 1.2 or other security features. For help on picking the right HttpClient, I wrote a blog post entitled The many flavors of HttpClient.

Summary

Pinning both the certificate and the TLS version will make it much harder to intercept the communication between your app and its backend. It should be employed whenever making calls to a backend within the control of the app developer.

A few weeks ago at Xamarin Dev Days Graz I was asked a question I’ve been asked many times before: How do I obfuscate my mobile app’s code? My answer is always a counter-question: What are you trying to achieve by obfuscating your code? I’ve gotten different answers to this question and I want to dig into some answers I’ve received in the past in this blog post series.

A common answer is that there is some key or certificate that needs to be protected in the code.

I don’t believe code obfuscation is a good solution to this problem. I believe there typically isn’t anything that requires obfuscation inside an app’s code. Any attempts at hiding things inside an app’s code will only increase the effort it takes to get at that information but will not prevent it.

Some solutions I’ve heard for hiding a key inside the app code:

Encrypt the key (using which key?)

Assemble the key from strings in different portions of your source code

Hide the key in the last bytes of an embedded image

Use a code obfuscation tool

Don’t put it into the app’s code at all but load the key from a backend after the app has been installed

Let’s look at API keys

Let’s look at why these keys are there in the first place. In most cases, the key is used to authenticate the app towards a backend which is commonly referred to as an API key. For example, if you look at the Parse SDK Getting Started in the Xamarin Component Store, you’ll find this:

What the API expects here is a unique app ID and a key. The key gives you access to your data on the backend. The big problem here is that this one key is being used by all instances of the app.

A team at the University of Paderborn did an experiment to see if they could find that key inside app bundles in the Google Play store for apps that were using Parse. Using a simple static code analysis was enough for some apps but combining that with a dynamic (runtime) analysis was enough to retrieve the API key for all apps that were analyzed. Think about it: At some point, the app will have to call the method ParseClient.Initialize() with the plaintext key in memory.

The team then went on to analyze what they could access using those extracted API keys. The least information they could get for each app was a list of verified user email addresses. In many cases, they had complete read or even write access to all database tables for each app’s backend. The data found ranged from pictures, location information, contact information, and sales information to data gathered by trojans (yes, even the bad guys used Parse as a backend).

Parse is just an example here. You can find these API keys used in many backends and there is hardly an app out there that does not use any API keys. Anyone who extracts that API key can do whatever is allowed with that API key. This may or may not be a problem depending on what type of API key is at hand. It’s important to put yourself into the position of an attacker: What could someone who gets ahold of your API key do with that key?

In the case of Parse, it would have been possible to add user management and additionally authenticate users to access resources. That way, the API key itself would not have allowed access to all this data.

Authenticate the user, not the app

If you’re designing your own backend, you need to think about what type of data it is you are exchanging with your backend. Sometimes it may be OK to have your app access data from the backend without providing any credentials. This may be true for information you could also put on an unauthenticated website. But many times, you will be exchanging non-public information with your backend. In this case, it is always better to authenticate not the app but each user. The advantages are:

You can fully control what each user can see, even after your app has been distributed.

You can revoke access for individual users without breaking access for all other users.

If an API requires an API key, call it from your backend

If you do have to use a service that requires an API key, it is usually best to not make that call from within your app. A better approach is to make an authenticated user request the information from your own backend and then let your backend make the 3rd party API call on behalf of the user. The advantages here are:

It is not possible for an attacker to extract the API key and use your account to access the 3rd party API.

You can control how many calls are made with your API key.

You can cache results from the API and reduce the number of calls necessary.

You can block individual users from using the 3rd party API.

To hear more about this topic, you can watch my Xamarin Evolve talk on app security or stay tuned on this channel for more posts in this blog series.

HttpClientHandler

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 mtouch (e.g., --http-message-handler=NSUrlSessionHandler).

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 Xamarin.Android.Net.AndroidClientHandler.

Alternatively, you can use ModernHttpClient by handing a NativeMessageHandler to the HttpClient constructor which will also use native implementations for making HTTP calls.

SSL/TLS

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 mtouch‘s options.

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.

Update (2017-02-15)

Here’s an update on the current state of HttpClient:

You can now specify that you want to use AndroidClientHandler your Android project’s properties page, just as you already could for iOS.

As expected, Xamarin have added TLS 1.2 support to the Mono (non-native) HttpClientHandler by incorporating Google’s BoringSSL into their codebase. For Android, this option is also selectable in your project’s properties page. BoringSSL also brings TLS 1.2 to the Unix/Linux implementations of Mono.

Contrary to my previous knowledge, ModernHttpClient does support certificate pinning using ServicePointManager. Thomas Bandt wrote an excellent blog post on how to get certificate pinning working with ModernHttpClient and even AndroidClientHandler.

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?