Tag Archives: Certificate Pinning

#wedskaas: What every developer should know about app security, part 3: Inspecting your app’s traffic with Fiddler

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.

Point Mobile Safari at http://ipv4.fiddler:8888/ while your phone’s proxy server is set to Fiddler.

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.

Other post in this series

#wedskaas: What every developer should know about app security, part 2: Why you should be using certificate pinning

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:

If you’re using Azure Websites as your backend, here’s an article on how to disable older TLS versions.

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.

Other post in this series