SSL Pinning in Swift
Every Mobile application needs to retrieve information from the server to display it to the user. However, there can be some sensitive information shared between the application and the Server, for example, the username and password of the user.
With iOS 9, Apple provided App Transport Security (ATS), which forces the application to maintain a secure network connection by adopting HTTPS protocol and Transport layer security. This makes the application not communicate with a non-secure (http) connection. However, it is possible to bypass App Transport Security by setting up man-in-the-middle attacks that may use self-signed certificates. In this article, we will discuss how we can implement SSL pinning in iOS applications to secure network connections. We will also cover the basics of Transport Layer Security and man-in-the-middle attacks.
Transport Layer Security
Apple provides us App Transport Security (ATS), which allows us to transmit data over a secure (HTTPS) network by implementing Transport Layer Security (TLS). It enables us for the data sharing over a secure network in the following three steps.
- The connection is initiated from the client by sending the payload, which includes the supported version of TLS and cipher suite, which is being used for encryption. The Server sends the selected cipher suites and a digital certificate in the response, which is verified at the client’s end whether the digital certificate is authentic or not.
- If the digital certificate is verified successfully at the client’s end, then it generates a pre-master key encrypted with the Server’s public key included in the certificate. The Server uses its private key to decrypt the secret, which is used to generate a master key.
- The client and server use plaintext encryption and cipher text decryption by using the private key.
In this process, the client trusts the digital certificate provided by the Server. A certificate works as identity proof for the Server. A certificate is a text file that contains the Server’s information and follows X.509 standard. It must be signed by the trusted certificate authority.
Man-In-The-Middle Attack
In a man-in-the-middle attack, the attacker sets up an SSL proxy server to intercept the data being sent by the client to Server. The SSL proxy performs the encryption and decryption between the client and the Server. For example, Charles, which is a proxy server, works between the app and the Server and intercept the data for testing purpose. Charles works in the following phases.
- The data is encrypted at the application’s end using Charles ProxyCertificate’s public key instead of using Server’s public key.
- Charles decrypts all the data with its private key and communicates with the Server with Server’s public key. Here, any developer can read the data which is being sent by the app to Server.
SSL Pinning
SSL Pinning is a technique used in swift to prevent man-in-middle attacks. In this process, the app validates the Server’s certificate again after the SSL handshaking. There is a local copy of trustful certificates maintained at the client’s end and compare them with the Server’s certificates at runtime. The connection is aborted in case if a mismatch between Server’s certificates and local copy occurs.
One disadvantage of this technique is, it requires an app update whenever the pinned certificate expires. However, we can also violate this by also pinning future certificates in the application. Instead of pinning the whole certificate, we can use the hashed public key, which will be the same across the future certificates.
SSL Pinning is performed in the following two steps.
- The certificate’s digital signature is validated first. The app may use any of the embedded root certificates, or we can supply our certificate.
- We must test the certificate against the trust policy.
To implement SSL Pinning in the iOS application, we need to have a SecTrust object, which will be prepared with one or more certificates and policy objects. The SecCertificate object is provided by Apple to represent a X.509 certificate. We can retrieve the certificate from a bundle by using the following code.
As we now have a certificate, we can prepare a policy or use a standard basic policy for X.509 certificates. Consider the following code to prepare a policy.
We can also create our policy by calling SecPolicyCreateSSL(_:_: ), which accepts Server (bool) and hostname.
Apple provides SecTrust object to validate both certificates and policies. Implement the following code to validate certificates and policies.
We need to evaluate the SecTrust that we receive during a network call with the policies and compare the certificate with the pinned certificate.