SSL pinning in iOS app are required stop Man In The Middle Attack (MOM). There are only two ways to do SSL pinning are using public key and SSL certificate
HTTPS already provides secure communication, then why do we need SSL Pining in iOS Apps? Isn’t HTTPS secure enough?
***To get familiar with HTTPS, have a look on my article how HTTPS works under the hood.
HTTPS is secure enough no doubt about it! It makes sure communication between server and client is safe and data is not tempered while on transit.
Just that it doesn’t guarantee, that client is communicating with the right server, the server which is meant to be communicating with this client, the server we know.
Because of the only weak link in the chain is blindly trusting on third party validator(Browser or OS) to validate the certificate for us. In case of iOS app it relies on iOS Trust Store. A Man in the Middle Attack is always a possibility in this kind of scenario. An attacker can generate a self-signed certificate and include it in the iOS Trust Store or hack a root CA certificate.
Another problem is risks of mis-issuance of SSL certificate. In 2011, the Dutch CA DigiNotar was hacked, in what is probably the largest compromise of a public CA. A hacker was able to access their internal systems and issue certificates for any site.
The idea of certificate/public key pinning is to stop relying on these third-parties (certificate authorities, operating systems, browsers) to validate the identity of the backend server and to take matters into our own hands.
So, what is certificate pinning?
Pinning is keeping the information about the certificate in the client locally to validate against the ssl certificate we get while calling the api for server authenticity. However it is highly recommended not to store the certificate information in the app bundle, rather keep a Hash of certificate info. Why hash is so important, is explained down below.
Hashing is kind of one way street. You never get back the original data from the hashed data, however if you have same data you can create an exactly same hash again and again. One more benefit of keeping a hash is you can even keep a future certificate info also, without revealing the real certificate information ahead of time.
There are two options available for pinning:
— Certificate: This is simple and easy to implement. An SSL certificate information stored (generally hashed) in our app/website and validated against the server certificate. Only drawback of this method is certificate gets expired in a year or two.
Generally companies like google changes the certificate in a month or two even though it’s not expired for security reasons. In case of mobile app to pin a new certificate, a new version of app with renewed certificate needs to be pushed to app-store, and even if you do so with great difficulty, you still will have few users left behind, who don’t update their apps as frequently, for those users app will become unusable. It needs a force update which is not a good user experience.
— Public key : Public key of an SSL certificate is extracted and pinned in this method and, validated against the public key of server SSL certificate. One benefit of using only public key instead of above mentioned method of certificate pinning is a public key can remain same even after renewing the certificate. Which eliminates the problem of updating the app with renewed certificate.
In either case, we will not store the actual certificates and/or public key in the app, it is recommended to create sha256 hash of these and pin instead.
Demonstration of SSL pinning is done using an iOS app, you can checkout the SourceCode. However will explain the steps taken for the process of SSL certificate/public key pinning:
Step-1: Command to obtain a certificate from a domain/api:
openssl s_client -showcerts -connect www.bitmountn.com:443 < /dev/null | openssl x509 -outform DER > bitmountn.cer
Step-2: Include that certificate in App bundle.
Step-3: Extract the public key using openSSL command
openssl x509 -inform der -in bitmountn.cer -pubkey -noout
or
Step-3: Extract the public key using Swift Code:
Extracts public key from SSL certificate.
Step-4: Create sha256 hash of certificate or public key:
Create sha256 hash from different formats like Data, String, SecCertificate.
or
Step-4: Create a sha256 has from pinned certificate
Load the pinned SSL certificate in SecCertificate format.
Step-5: Follow URLSessionDelegate protocol and implement URLAuthenticationChallenge method:
This function is where we need to verify Server by extracting SSL certificate of server/api and validating against pinned ssl certificate.
When attacker tries to hack the server SSL certificate using self signing certificate or by replacing the root certificate available in the trust store of iPhone, we get to know by validating against pinned certificate/public key and reject the Auth Challenge, which in turn stops url connection.
Complete demo project about SSL pinning available on GitHub, you can checkout the Source Code.
Also you can check our article on optimise memory by knowing How ARC works in Swift.
Reference: Dzone, Stackexchange