Preventing man-in-the-middle attacks

TLS certificate pinning on mobile apps to secure from MiTM attacks

Pete McCain
certificate pinning
© Shutterstock /hywards

Mobile security has become more important than ever, especially as many employers adopt Bring Your Own Device for remote and in-house employees. What is TLS certificate pinning? Find out all about it and how to implement TLS pinning on Android and iOS apps and prevent man-in-the-middle (MiTM) attacks on mobile apps.

With the increase in the use of smartphones, mobile security has become one of the top-most concerns for companies. Many employers are adopting ‘Bring Your Own Device’ (BYOD) that authorizes their remote, as well as in-house, employees to use their personal devices such as smartphones, laptops, and tablets to access official classified data. This, in turn, increases the chances of data breaches.

In fact, the Cost of a Data Breach Report 2019 revealed that businesses incur a loss of approximately $3.92 million as a consequence of data breach.

However, there is another popular malicious practice called Man-in-the-middle Attack, similar to eavesdropping, where a hacker sneaks into a conversation between two individuals and tampers with the information. This operation occurs when data is transmitted between an app and a server.

Mobile-app developers employ servers – secured by Transport Layer Security (TLS) – to ferry information between an app and its users. In the meantime, developers place these certificates in their Android and iOS apps- as a sole measure of safety- to prevent their app from invasion. This reliance on certificates, however, works in favour of hackers who set up man-in-the-middle (MiTM) attacks by using self-signed or hacked certificates to track users’ data. 

How MiTM attacks mobile apps

Almost always, apps are downloaded from the app store, where they are monitored for threats at timely intervals. Still, apps could be vulnerable to attacks when they are not under observation. This makes it difficult for app-store auditors to gauge threats at an early stage, resulting in a MiTM attack.

SEE ALSO: How DevOps can migrate to the cloud without sacrificing security

Data transmitted between the server and destination, during that time, can be interrupted, copied, and used by hackers. For instance, if you are using a banking app, a hacker can crack your password and view your transactions.

For most of the part, third-party apps, available outside the app store, do not adhere to security standards. Having said that, some developers adopt TLS pinning to protect the app from potential dangers. However, this measure does not apply during the download and install process, and attackers replace or remove the original certificate by encrypting it in MiMT attacks.

What is TLS certificate pinning?

TLS (Transport Layer Security) certificate pinning is a process applied to enhance the security of a mobile application, for it authenticates the certificate configured on the server.

TLS pinning offers additional security when a connection is established with a server during the TLS handshake. It verifies the identities of the client and the server before the completion of the process. Furthermore, in case of discrepancies, the connection is discontinued, and the server is sent a warning.

How to implement TLS pinning on Android and iOS apps

What’s important, first, is to decide whether you want the TLS certificate or the public key to be pinned to the application code. Oftentimes, developers resort to pining the public key owing to the convenience of managing it when the server certificates are replaced. However, that would make your app’s data vulnerable should there be a MiMT attack.

Certificate pinning for Android

There are only a handful of manual methods trusted by CAs that are used to install certificate pinning for Android apps. The Android Developer has introduced a new technique for certificate pinning that includes hashes of certificates’ public keys and their backup keys in res/xml/network_security_config.xml. These backup keys are useful to maintain the app usage when certificate pinning and keys are replaced. This will prevent you from updating your app in these cases. 

Here is the code for network_security_config.xml file:

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

There are several third-party libraries available to deploy certificate pinning in Android apps. Among them is OkHttp, the most-used library, that can easily be configured by creating a “CertificatePinner” class.

Code from OkHttp:

     String hostname = "";
     CertificatePinner certificatePinner = new CertificatePinner.Builder()
     OkHttpClient client = OkHttpClient.Builder()

     Request request = new Request.Builder()
         .url("https://" + hostname)

This will show an error as expected, for a false SHA256 value. Certificate pinning failure!
   Peer certificate chain:
     sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=:, OU=PositiveSSL
     sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=: CN=COMODO RSA Secure Server CA
     sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=: CN=COMODO RSA Certification Authority
     sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=: CN=AddTrust External CA Root
   Pinned certificates for
   at okhttp3.CertificatePinner.check(
   at okhttp3.Connection.upgradeToTls(
   at okhttp3.Connection.connect(
   at okhttp3.Connection.connectAndSetOwner(

Now, to get this code to work, you need to configure SHA256 hashes into the “CertificatePinner” class.

     CertificatePinner certificatePinner = new CertificatePinner.Builder()
       .add("", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
       .add("", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=")
       .add("", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=")
       .add("", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=")

Certificate pinning for iOS

Certificate pinning on iOS can be set-up by using “NSURLConnectionDelegate” and  “NSURLConnection”. For more insights on its implementation, you can read OWASP Certificate and Public Key Pinning Technical Guide.

SEE ALSO: Report & interview: Plan your container security as a core component

Furthermore, iOS certificate pinning can be implemented using TrustKit library which can also be used for Android. The code below enables certificate pinning in iOS apps.

   NSDictionary *trustKitConfig =
   kTSKPinnedDomains : @{
           @"" : @{
                   kTSKExpirationDate: @"2017-12-01",
                   kTSKPublicKeyHashes : @[
                   kTSKEnforcePinning : @NO,
                   kTSKReportUris : @[@""],
           @"" : @{
                   kTSKPublicKeyHashes : @[
                   kTSKIncludeSubdomains : @YES

   [TrustKit initSharedInstanceWithConfiguration:trustKitConfig];
   trustKit = [TrustKit sharedInstance];

The following code can be deployed in Swift:

       let trustKitConfig = [
           kTSKSwizzleNetworkDelegates: false,
           kTSKPinnedDomains: [
               "": [
                   kTSKExpirationDate: "2017-12-01",
                   kTSKPublicKeyHashes: [
                   ],]]] as [String : Any]


Here, both AlamoFire and AFNetworking can be used as a third-party library for iOS certificate pinning.


In conclusion, I’d recommend you run regular checks for third-party libraries’ updates and to upgrade to new versions of TLS.


Pete McCain

Pete McCain is a technology startup mentor associated with AppVelocity – Canada-based mobile app development company. He has collaborated with more than 50 entrepreneurs — over the last decade — to maximise growth and contribute to technical excellence. Connect with him on Twitter.

Inline Feedbacks
View all comments