Certificate Pinning your Android and iOS apps.

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 send between our client and our server, could be risky.
By default, when making a TLS connection, the client check two things:

  1. The server’s certificate matches the requested hostname.
  2. 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 a unsafe certificate is installed, someone could do a man-in-the-middle attack.

图片[1]-Certificate Pinning your Android and iOS apps. - 拾光赋-拾光赋
The solution to this problem is certificate pinning: storing a certificate on our client to ensure that any SSL request made matches the one our server has. Let me explain you how to do it on both Android and iOS apps.

 Android

OkHttp lib provide a CertificatePinner class to be added to an OkHttpClient instance. The easiest way to pin a host is turn 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();

Enter fullscreen mode Exit fullscreen mode

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)

Enter fullscreen mode Exit fullscreen mode

The exception will provide you the server’s certificate public key hashes. Paste them on the CertifinatePinner and done! ✔

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();

Enter fullscreen mode Exit fullscreen mode

iOS

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 -servername mydomain.com -connect mydomain.com:443
 </dev/null | openssl x509 -outform DER > mydomainCert.der

Enter fullscreen mode Exit fullscreen mode

And now, lets 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
  ),
]

Enter fullscreen mode Exit fullscreen mode

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!))

Enter fullscreen mode Exit fullscreen mode

Done! ✔. Just use this sessionManager object to execute request

sessionManager.request("https://mydomain.com/api", method: .get, headers: headers)...

Enter fullscreen mode Exit fullscreen mode

Feedback is welcome! Hope it’s useful ☺️

Sources

OkHttp: https://github.com/square/okhttp/wiki/HTTPS
Alamofire: https://github.com/Alamofire/Alamofire#security

原文链接:Certificate Pinning your Android and iOS apps.

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容