SSL Pinning is a security technique where the application verifies the server certificate against a pre-known fingerprint or certificate, rather than relying on the CA chain of trust. Unlike standard verification, pinning prevents traffic interception through fraudulent root certification authorities. According to the OWASP Mobile Security Testing Guide (2025), this technique is in the top-3 recommended controls for protection against MITM attacks. Without pinning, an attacker with a fraudulent root certificate can decrypt all HTTPS traffic of the application.
Key Takeaways
SSL Pinning is a security mechanism where a mobile or web application remembers a trusted server certificate or public key and rejects any connections whose certificate does not match the stored one. In the standard HTTPS scheme, the client verifies the certificate through a trust chain up to the root CA — any CA can sign a certificate for any domain. SSL Pinning eliminates this weakness: instead of trusting hundreds of CAs, the application trusts only one specific certificate.
The problem with standard verification is that any of hundreds of root CAs can issue a valid certificate for your domain — accidentally or under duress. An attacker who gains access to a corporate proxy with its own root certificate can conduct a MITM attack without browser warning. SSL Pinning closes this vulnerability: even if a CA issues a fraudulent certificate, the application will reject it because the fingerprint does not match the recorded one.
In mobile applications, SSL Pinning is especially important because devices often operate on unsecured networks — public Wi-Fi, corporate proxies with traffic inspection, infected access points. According to the Verizon Mobile Security Index (2025), over 60% of data breaches in mobile applications are related to traffic interception at the transport layer.
Mobile applications transmit sensitive data — authentication tokens, payment information, personal user data. Without additional protection, HTTPS can be compromised through root certificate substitution on the device — for example, after installing a corporate profile or malicious application. SSL Pinning ensures that even if a fraudulent root CA is installed on the device, the application will continue to verify the certificate against its own whitelist.
The SSL Pinning process consists of three stages: fingerprint capture, connection verification, and error handling. During development, the engineer obtains the SHA-256 fingerprint of the server certificate (openssl x509 -fingerprint -sha256) and embeds it into the application code or configuration file. With each HTTPS request, the application computes the fingerprint of the received certificate and compares it with the stored one — if the values do not match, the connection is terminated.
The first stage is pinning at build time: the developer knows the server certificates in advance and embeds their hashes. The second stage is pinning on first connection (trust on first use, TOFU): the application remembers the certificate on the first request and uses it to verify all subsequent ones. TOFU is convenient for dynamic environments but is vulnerable on the first attack — if the first connection is already intercepted, the fraudulent certificate will be accepted as trusted.
A critical detail is backup pins. Certificates have an expiration date, and when they are replaced, the application without an update will lose connection to the server. Engineers include 2–3 additional fingerprints — for example, a backup certificate fingerprint and a root CA fingerprint. If the main certificate changes, the application checks against backup pins, and the connection continues to work.
# Obtaining the SHA-256 certificate fingerprint
openssl s_client -connect example.com:443 </dev/null 2>/dev/null | \
openssl x509 -pubkey -noout | \
openssl pkey -pubin -outform der | \
openssl dgst -sha256 -binary | \
base64
There are two main approaches to implementing pinning: certificate pinning (binding to the entire certificate) and public key pinning (binding to the public key). Each approach has its own strengths and limitations that affect security and maintainability.
| Type | Object of Binding | Flexibility | Security |
|---|---|---|---|
| Certificate Pinning | Entire X.509 certificate | Low — requires update when certificate changes | High — precise binding |
| Public Key Pinning | Public key of the certificate | Medium — the key may be in a new certificate | High — less sensitive to certificate details |
| Hash Pinning | SHA-256 hash of certificate or key | High — can change certificates without changing the key | Medium — depends on hash strength |
Certificate pinning is the strictest method. The application stores a copy of the trusted certificate or its SHA-256 fingerprint and compares it with the server certificate on each HTTPS connection. This method provides maximum security but creates problems during rotation — certificates typically last 1–2 years, after which a forced application update is required. Recommended for critical systems with a controlled update cycle.
Public key pinning is a more flexible approach. Instead of the entire certificate, the application remembers only the server's RSA or ECDSA public key. The key can remain unchanged when the certificate is re-issued, if the company uses the same key pair. This reduces the frequency of application updates. However, if the key is compromised, a cascade replacement on all clients will be required.
On the Apple platform, SSL Pinning is implemented through the URLSession delegate. The developer creates a class implementing the URLSessionDelegate protocol and overrides the didReceive challenge method, where they manually verify the server certificate against stored fingerprints. An alternative approach is using Alamofire with ServerTrustManager, which simplifies configuration.
class SSLPinningDelegate: NSObject, URLSessionDelegate {
let pinnedHash = "sha256/Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg="
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust
else { return completionHandler(.cancelAuthenticationChallenge, nil) }
if validate(serverTrust, pinnedHash) {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
In the example, the delegate receives an authentication request from URLSession, extracts serverTrust from the challenge, and compares the SHA-256 fingerprint of the certificate with the stored one. If the fingerprint matches — the connection proceeds, otherwise the challenge is rejected. For production, it is worth adding verification of multiple backup pins and error logging for monitoring.
Starting with iOS 14, Apple added built-in support for Certificate Pinning through Info.plist. The developer specifies trusted certificates in the NSAppTransportSecurity key with the NSPinnedDomains sub-dictionary. This approach does not require writing code but is less flexible — it is impossible to dynamically change pins or log verification errors.
On Android, there are three main ways to implement SSL Pinning: through the OkHttp library's CertificatePinner, through Network Security Config in XML, and through custom verification in HttpsURLConnection. OkHttp is the most popular and recommended approach, used in Retrofit and other HTTP clients.
val certificatePinner = CertificatePinner.Builder()
.add("api.example.com",
"sha256/Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg=")
.add("api.example.com",
"sha256/FiPq6ePEsVRqZ1yW0F6wLgWi24BE7j5qLk0iL=") // backup pin
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
In the OkHttp configuration, the developer specifies the domain and one or more SHA-256 fingerprints. On the first fingerprint, OkHttp compares the server certificate with the specified pins. If there is no match, the client throws SSLPeerUnverifiedException. A backup pin is mandatory — without it, when the certificate changes, API requests will immediately start failing.
Android supports declarative Certificate Pinning through XML configuration starting from API 24. The file res/xml/network_security_config.xml contains a list of domains and their fingerprints. This method is convenient for static configurations but does not allow implementing TOFU or custom verification logic with logging of anomalies.
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<domain-config cleartextTrafficPermitted="false">
<domain includeSubdomains="true">api.example.com</domain>
<pin-set expiration="2027-12-31">
<pin digest="SHA-256">
Wi24BE7j5qLk0iLvPq6ePEsVRqZ1yW0F6wLg=</pin>
<pin digest="SHA-256">
FiPq6ePEsVRqZ1yW0F6wLgWi24BE7j5qLk0iL=</pin>
</pin-set>
</domain-config>
</network-security-config>
SSL Pinning significantly increases the security of a mobile application but introduces operational complexities. The main advantage is protection against MITM attacks even when root CAs are compromised. The application trusts only those certificates explicitly specified by the developer, not the entire infrastructure of public certification authorities. This is especially critical for financial applications, messengers, and applications with sensitive data.
The main drawback is the complexity of certificate rotation. If a certificate expires or is revoked, users without an application update lose connection. This is solved through backup pins and a gradual update mechanism: the new application knows both the old and new certificates, and after a full update of users, the old pin is removed from the code. It is recommended to include at least 2 backup pins — one for the current certificate, one for the future.
Another compromise is the inability to use public proxies for traffic debugging (Charles Proxy, Burp Suite) without disabling pinning. This complicates debugging of network requests during development. The solution is conditional compilation: pinning is disabled in debug builds and enabled in release builds. OWASP recommends using the BuildConfig.DEBUG flag for switching.
| Aspect | Advantage | Disadvantage |
|---|---|---|
| Security | Protection against MITM through fraudulent CAs | Complexity when a key is compromised |
| Maintenance | Explicit trust control | Rotation requires application update |
| Debugging | Guaranteed connection to the correct server | Blocks debugging proxies |
Frequently Asked Questions
Standard HTTPS verification trusts any certificate signed by a known root CA. SSL Pinning trusts only a specific certificate or key — if a CA issues a fraudulent certificate, the application will reject it.
Certificates typically last 1–2 years. It is recommended to update pins 3–6 months before the current certificate expires, adding the new fingerprint as a backup pin, and removing the old one after rotation.
Yes, but keep in mind that CDNs may change certificates when switching between edge servers. It is recommended to pin to the public key rather than a specific certificate, and use multiple backup pins.
The connection is terminated with an error — on Android this is SSLPeerUnverifiedException, on iOS the challenge is rejected with .cancelAuthenticationChallenge. The application should properly handle this error and notify the user.
No, but OWASP recommends it for applications handling sensitive data: banking, healthcare, corporate systems. For simple read-only applications, standard HTTPS verification with EV certificates is usually sufficient.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also