Man in the middle attacks (MITM) is one of the attacks where the attacker interrupts between the sender and receiver and gathers the sensitive data. MITM attacks, which are a form of session hijacking are not new. However, what might not be known is that mobile devices are vulnerable to MITM attacks too. It is quite complex for the attacker to inject the MITM attack on mobile applications than on web applications.
A man-in-the-middle attack (MITM) is like eavesdropping. Data is sent from point A (Mobile) to point B (server/website), and an attacker can get in-between these transmissions. They then set up tools programmed to “listen in” on transmissions, intercept data that is specifically targeted as valuable, and capture the data. Sometimes this data can be modified in the process of transmission to try to trick the end user to expose sensitive information, such as login credentials. Once the user has fallen into the trap, the data is collected from the target, and the original data is then forwarded to the planned destination unaltered.
For mobile apps to prevent these types of attacks it is important to look at how the mobile app performs authentication. Using certificate pinning within the mobile app helps ensure that the mobile app is communicating with the device it is expecting to communicate with.
- ARP Poisoning
- DNS Spoofing
- Port stealing
- Invisible Proxy
- Certificate Forgeing
In this blog, we will discuss the major attack (SSL PINNING)
Certificate pinning is hard-coding the certificate known to be used by the server in the mobile application. The app can then ignore the device’s trust store and rely on its own, and allow only SSL connections to hosts signed with certificates stored inside the application.
The client makes a connection to the server and the server responds with its SSL certificate. If that certificate was issued by a Certificate Authority that is trusted by the OS, then the connection is allowed.
When we, developers, are working in the development of any kind of software, we can’t forget about security. The minimum security measure we should use is HTTPS as the protocol to share information between a client (in this case, an Android/iOS app) and a server, followed by an updated cryptographic protocol like TLS 1.2 (SSL 3.0 is vulnerable!)
You may think that using an HTTPS is enough but in some cases like banking applications, where sensitive data may be sent between our client and our server, could be risky.
By default, when making a TLS connection, the client check two things:
- The server’s certificate matches the requested hostname.
- The server’s certificate has a chain of truth back to a trusted root certificate.
What it doesn’t do is check, if the certificate is the specific certificate you know your server is using, and that’s a possible security vulnerability, if the client is compromised and an unsafe certificate is installed(certificate forging), someone could do a man-in-the-middle attack.
Root CA, intermediate CA and Medium certificate
The solution to this problem is certificate pinning. Storing a certificate on our client application to ensure that any SSL request made matches the server’s certificate provided by a trusted CA (certificate authority). Let us see how to do it on both Android and iOS apps.
OkHttp lib provides a CertificatePinner class to be added to an OkHttpClient instance. The easiest way to pin a host is turned on pinning with a broken configuration and read the expected configuration when the connection fails.
CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("mydomain.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=") .build(); OkHttpClient client = OkHttpClient.Builder() .certificatePinner(certificatePinner) .build();
After a request is executed, you’ll see this message on the console:
javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure! Peer certificate chain: sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=: CN=mydomain.com, 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 mydomain.com: sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= at okhttp3.CertificatePinner.check(CertificatePinner.java) at okhttp3.Connection.upgradeToTls(Connection.java) at okhttp3.Connection.connect(Connection.java) at okhttp3.Connection.connectAndSetOwner(Connection.java)
The exception will provide you the server’s certificate public key hashes. Paste them on the CertifinatePinner and done! Once the certificate pinner function is enabled in the Android app it will have protection against SSL MITM attacks
CertificatePinner certificatePinner = new CertificatePinner.Builder() .add("mydomain.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=") .add("mydomain.com", "sha256/klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=") .add("mydomain.com", "sha256/grX4Ta9HpZx6tSHkmCrvpApTQGo67CYDnvprLg5yRME=") .add("mydomain.com", "sha256/lCppFqbkrlJ3EcVFAkeip0+44VaoJUymbnOaEUk7tEU=") .build();
The iOS solution is not so straightforward because you need to store the certificate itself inside your app. In my case, I’ve used Alamofire as HTTP client lib for Swift.
First, you need to get the server’s certificate in .der format and add it to your iOS project.
openssl s_client -showcerts -server name mydomain.com -connect mydomain.com:443 </dev/null | openssl x509 -outform DER > mydomainCert.der
And now, let’s enable certificate pinning: to do it we need both ServerTrustPolicy and SessionManager objects. The first one will define the hostname and certificates that will be used in the process:
var serverTrustPolicies = [ "mydomain.com": .pinCertificates( certificates: ServerTrustPolicy.certificates(), validateCertificateChain: true, validateHost: true ), ]
ServerTrustPolicy.certificates() will return all stored certificates and the booleans will validate the certificate chain and the hostname.
Lastly, create a SessionManager object using this trust policies:
var sessionManager = SessionManager(serverTrustPolicyManager: ServerTrustPolicyManager(policies: serverTrustPolicies!))
Done! Just use this sessionManager object to execute request
sessionManager.request(“https://mydomain.com/api”, method: .get, headers: headers)…
Since MITM attacks are stealthier and it does not need any physical access to the victim device, a robust protection mechanism is required to prevent it. Hence SSL pinning is a much needed robust protection as it protects the application against MITM attacks by only allowing the connections to the server based on the trusted CA certificates.