SSL Pinning in Android

Bita Mirshafiee
7 min readDec 4, 2020

--

In this article we are going to see why SSL Pinning is needed, How it works, How we can implement it and test it.

why SSL Pinning is needed

First let’s see How client(here android device) and server will be connected.

On a mobile device when you want to connect to the server, a certificate check will be happened, in less than a second and in every connection that is being made.

In this certificate check, the mobile device make sure that the server that it is going to be connected to has the authorized certificate which the android device can accept.

You can see these pre-installed certificates in Settings > View Certificate Security.

This will be something like this:

These are the certificates that an android device can trust, so if the server certificate is not in this list, connection will be refused.

Ok so far we understood how the connection between the client and the server is being checked by certificates. now let’s see how an attacker could break this trust.

Man-In-The-Middle

You may heard of Man-In-The-Middle before, but now let’s see what is it, and How it could break the trusted connection.

So let’s go deep in the connection between the client and the server.

as we said in creating a connection between the mobile device and the server the decision that the server is trusted or not is being made in less than a second by the device.

The server certificate has two keys, which will be generated by an RSA algorithm:

One is the private key, which as the names says is private and is always being secured by the server, no one knows about it.

Two is a the public key, which everyone could access it, but no one can generate the private key by accessing the public key.

when a connection between the client and the server happens, the client gets the public key from the server, because with this public key the client can decrypt the data that is being exchanged between the client and the server.

Now let’s see how an attack could happen :

The attacker comes in between our server and client like below

The attacker has a fake trusted certificate too, so the device trusts it.

then the device gets the attackers certificate public key and just like this our data could be encrypted by the attacker, as easy as this.

This attack called Man-In-The-Middle, and with this technique our data could be read.

So, what is the solution?SSL Pinning.

How SSL Pinning Works?

As the name says, it pins the real public key that our trusted server has on our application on the device. this could be one public key, or if we have several servers so we have several public keys and we pin all of them.

In our mobile device we tell the application to just make trusted connections with servers that not only have trusted certificates but also have the predefined trusted public keys.

So, now no attacker can give it’s public key to our app to decrypt our data, because we only trust some specific public keys from our servers, that has been pinned on our app.

So now that we understood How SSL Pinning works, let’s see how we can implement it in our apps.

Implementation

Here I am going to talk about two different implementations of SSL Pinning:

First Implementation :

if you are using Okhttp Library you can easily delegate the process to be handled by this library like below:

val certificatePinner: CertificatePinner = CertificatePinner.Builder()
.add(baseUrl, publicKey)
.build()
client.certificatePinner(certificatePinner)
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()

Second Implementation :

In this implementation which is the recommended implementation, we are going to use Network Security Config which is just available for Api level 24 and higher.

First create an xml folder in resource file.

Then in xml folder create an xml file called exactly network_security_config.xml.

and inside :

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<pin-set expiration="2022-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
</network-security-config>

make sure to always have a backup pin in case you forced to switch to new keys or change CAs.

then in your Manifest.xml file :

add the below line and refer to network_security_config.xml file in application tag:

<application
//...
android:networkSecurityConfig="@xml/network_security_config"
//...

That will be it.

and if you want support for api level 23 and below you can take a look at this Github library TrustKit.

Test SSL Pinning

The important part is to test whether your SSL Pining implementation works or not.

For this we are going to use Fiddler. Fiddler will act as a Man-in-the-middle so we can test our implementation using it.

Setup Fiddler to read http data

Step 1 : Download Fiddler and install it.

Step 2 : Click Tools > Fiddler Options > Connections.

Step 3 : make sure “Allow remote computers to connect” and “Act as system proxy on startup” is checked.

Step 4 : In tab HTTPS, if you want to read an https url make sure “Capture HTTPS traffic” is checked.

Step 4 : Restart Fiddler.

Now we want to connect our device with the targeted app, to our system running Fiddler, to see if we can read our app traffic or not, so let’s see how:

First found your system IP.

Second we are going to connect our device to the system, using this IP, now let’s how to setup the mobile device:

Step 1 : Go to Settings.

Step 2 : Tap Connections.

Step 3 : Tap Wi-Fi

Step 4 : Tap and select your current Wi-Fi network.

Step 5 : Tap Advanced to Modify it.

Step 6 : Put proxy to Manual.

Step 7 : Write your system Ip in Proxy host name.

Step 8 : Put Proxy port as the port you configure in fiddler on your system, say 8888.

Step 9 : Click on save.

Now to verify all these settings, we need to go to this Address :

http://ipv4.fiddler:8888/

type it in your browser, and you should see the below screen.

http://ipv4.fiddler:8888/

if you see the above screen everything has been setup successfully, and you should continue to the next step.

Download and Install Fiddler Root Certificate

Now we need to install Fiddler Root Certificate, as you saw in this http://ipv4.fiddler:8888/ url, we have a FiddlerRootCertificate in a red box.

Download it.

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.

Allow it.

and the Root certificate is installed.

So now we expect to see our app’s traffic in fiddler panel(if we don’t have SSL Pinning), But there is something that you need to take care of:

if you are testing your app on a mobile device with api level 23 and below, this will be okey.

But if you are testing your app on a mobile device with api level 24 and above there will be a problem.

Because of the android security config for android Api level 24 and above , which we have talked about in second implementation of SSL Pinning, android won’t trust the Fiddler Certificate installed on your app, So all we need to do is to tell our app to trust every Certificate, so that way we can read the traffic, and after our test has been done by fiddler, we can remove this configuration from our app, but how we can add this Network Security Config:

Step 1 : create an xml folder in resource file.

Step 2 : then in xml folder create an xml file called exactly network_security_config.xml.

and inside :

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">your.domain.com</domain>
<trust-anchors>
<certificates src=”user”/>
</trust-anchors>
</domain-config>
</network-security-config>

then in your manifest.xml file in application tag add the below line :

<application
//...
android:networkSecurityConfig="@xml/network_security_config"
//...

Now run the app.

1 : Select your Domain in the left Panel to see whether you can see any traffic or not.

2 : in the top panel on Raw tab you could see your Request body(if you don’t have SSL Pinning Implementation)

3 : in the Bottom panel on Raw tab you could see your Response body(if you don’t have SSL Pinning Implementation)

So one good way to see if your implementation has any effect is to :

First check your app without SSL Pinning Implementation and see the traffic.

Second check your app after the SSL Pinning Implementation and now you shouldn’t see any traffic.

So that was a simple explanation about what is SSL Pinning and Why we Mobile App Developers need it for our applications.

--

--