SSL Certificate Pinning Implementation Guide 2025
SSL certificate pinning is a critical security technique that protects mobile applications and sensitive communications from man-in-the-middle attacks by validating that the server's certificate matches a known, trusted certificate or public key. In 2025, with increasing sophistication of network-based attacks and the prevalence of compromised networks, certificate pinning has become an essential security control for high-security applications.
This comprehensive guide covers everything you need to know about implementing SSL certificate pinning, including strategies for iOS and Android, backup pin management, certificate rotation, and operational best practices.
Understanding SSL Certificate Pinning
What is Certificate Pinning?
Certificate pinning is a security mechanism where an application validates that the server's SSL certificate matches a pre-defined certificate or public key that has been "pinned" within the application. This prevents attackers from using fraudulent certificates, even if they're signed by a trusted Certificate Authority.
Why Certificate Pinning Matters
Traditional SSL/TLS validation relies on the system's trust store, which contains hundreds of trusted Certificate Authorities. If any of these CAs are compromised or issue fraudulent certificates, attackers can perform man-in-the-middle attacks. Certificate pinning mitigates this risk by:
- Reducing Attack Surface: Limits trust to specific certificates rather than all CAs in the system trust store
- Preventing MITM Attacks: Blocks attacks using rogue certificates, even if signed by trusted CAs
- Protecting Sensitive Data: Essential for banking apps, healthcare apps, and applications handling sensitive user data
- Compliance Requirements: Required by many security standards for high-risk applications
- Defense in Depth: Adds an additional security layer beyond standard SSL/TLS validation
Types of Certificate Pinning
There are several approaches to certificate pinning, each with different trade-offs:
- Certificate Pinning: Pin the entire certificate. Simple but requires app updates when certificates are renewed.
- Public Key Pinning: Pin only the public key. More flexible as the same key can be used across certificate renewals.
- Subject Public Key Info (SPKI) Pinning: Pin the hash of the Subject Public Key Info. Most recommended approach in 2025.
- Certificate Authority Pinning: Pin the CA certificate. Less restrictive but still more secure than trusting all CAs.
🎯 Recommended Approach for 2025
SPKI (Subject Public Key Info) pinning is the recommended approach. It provides the right balance of security and operational flexibility, allowing certificate renewals without app updates as long as the same key pair is used.
Implementing Certificate Pinning on iOS
iOS Native Implementation
iOS provides built-in support for certificate pinning through URLSession and App Transport Security (ATS):
// Swift Implementation - URLSessionDelegate
class PinningDelegate: NSObject, URLSessionDelegate {
let pinnedPublicKeyHash = "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// Evaluate server trust
let policy = SecPolicyCreateSSL(true, challenge.protectionSpace.host as CFString)
SecTrustSetPolicies(serverTrust, policy)
var secResult = SecTrustResultType.invalid
let status = SecTrustEvaluate(serverTrust, &secResult)
guard status == errSecSuccess else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// Get server certificate
guard let serverCertificate = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
// Extract public key
let serverPublicKey = SecCertificateCopyKey(serverCertificate)
let serverPublicKeyData = SecKeyCopyExternalRepresentation(serverPublicKey!, nil)! as Data
// Calculate hash
let serverHash = sha256(data: serverPublicKeyData)
// Compare with pinned hash
if serverHash == pinnedPublicKeyHash {
let credential = URLCredential(trust: serverTrust)
completionHandler(.useCredential, credential)
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
Using TrustKit for iOS
TrustKit is a popular open-source library that simplifies certificate pinning on iOS:
// TrustKit Configuration
let trustKitConfig = [
kTSKSwizzleNetworkDelegates: false,
kTSKPinnedDomains: [
"api.example.com": [
kTSKPublicKeyHashes: [
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" // Backup pin
],
kTSKEnforcePinning: true,
kTSKIncludeSubdomains: true
]
]
] as [String: Any]
TrustKit.initSharedInstance(withConfiguration: trustKitConfig)
iOS Best Practices
- Always include backup pins to prevent app lockout during certificate rotation
- Use SPKI pinning rather than certificate pinning for flexibility
- Implement proper error handling and fallback mechanisms
- Test thoroughly with both valid and invalid certificates
- Consider using certificate transparency for additional validation
Implementing Certificate Pinning on Android
Android Network Security Configuration
Android provides declarative certificate pinning through Network Security Configuration:
api.example.com
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=
Android Programmatic Implementation
For more control, implement pinning programmatically using OkHttp:
// Kotlin Implementation with OkHttp
val certificatePinner = CertificatePinner.Builder()
.add("api.example.com", "sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=")
.add("api.example.com", "sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=")
.build()
val client = OkHttpClient.Builder()
.certificatePinner(certificatePinner)
.build()
// Make request
val request = Request.Builder()
.url("https://api.example.com/data")
.build()
client.newCall(request).execute()
Android Best Practices
- Use Network Security Configuration for declarative pinning when possible
- Set appropriate expiration dates for pin sets
- Include multiple backup pins for certificate rotation
- Test on different Android versions and devices
- Implement certificate transparency validation
Certificate Rotation and Backup Pins
The Backup Pin Strategy
Always include backup pins to prevent application lockout during certificate rotation:
- Primary Pin: Current certificate's public key hash
- Backup Pin 1: Next certificate's public key hash (pre-generated key pair)
- Backup Pin 2: CA certificate public key hash or another backup key
⚠️ Critical Warning
Never deploy an app with only a single pin. If that certificate needs to be revoked or rotated unexpectedly, all app instances will be locked out with no recovery option except releasing a new app version.
Certificate Rotation Process
Follow this process for smooth certificate rotation:
- Pre-generate Keys: Generate the next certificate's key pair before current certificate expires
- Add Backup Pin: Include the new certificate's public key hash as a backup pin in the app
- Deploy App Update: Release app version with both current and new pins
- Wait for Adoption: Allow sufficient time for users to update (typically 3-6 months)
- Rotate Certificate: Deploy new certificate on servers
- Monitor: Watch for pinning failures and user reports
- Remove Old Pin: In next app version, remove the old pin and add next backup pin
Calculating Public Key Hashes
Generate SPKI hashes for pinning:
# Extract public key from certificate
openssl x509 -in certificate.pem -pubkey -noout > pubkey.pem
# Calculate SHA-256 hash of SPKI
openssl pkey -pubin -in pubkey.pem -outform der | openssl dgst -sha256 -binary | openssl enc -base64
# Output: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
Testing and Validation
Testing Strategies
Comprehensive testing is essential for certificate pinning:
- Valid Certificate Test: Verify app works with correctly pinned certificate
- Invalid Certificate Test: Confirm app rejects certificates with wrong pins
- Expired Certificate Test: Test behavior with expired certificates
- Self-Signed Certificate Test: Verify rejection of self-signed certificates
- MITM Proxy Test: Use tools like Charles Proxy or mitmproxy to simulate attacks
- Certificate Rotation Test: Validate smooth transition during certificate updates
Testing Tools
- Charles Proxy: SSL proxy for testing MITM scenarios
- mitmproxy: Open-source SSL proxy for automated testing
- Burp Suite: Security testing tool with SSL interception
- Frida: Dynamic instrumentation for testing pinning implementation
Monitoring in Production
Implement monitoring to detect pinning issues:
- Log pinning failures with error details
- Track pinning failure rates and trends
- Alert on sudden increases in pinning failures
- Monitor certificate expiration dates
- Track app version distribution for rotation planning
Common Pitfalls and Solutions
Pitfall 1: Single Pin Deployment
Problem: Deploying with only one pin creates risk of app lockout.
Solution: Always include at least two backup pins. Pre-generate key pairs for future certificates.
Pitfall 2: Pinning Leaf Certificates
Problem: Pinning entire certificates requires app updates for every renewal.
Solution: Use public key pinning (SPKI) instead, allowing certificate renewal with same key pair.
Pitfall 3: Insufficient Testing
Problem: Inadequate testing leads to production issues.
Solution: Implement comprehensive test suite covering all scenarios including MITM attacks.
Pitfall 4: No Rotation Plan
Problem: Lack of certificate rotation strategy causes emergency situations.
Solution: Develop and document certificate rotation procedures. Schedule rotations well in advance.
Pitfall 5: Ignoring Certificate Transparency
Problem: Missing additional validation opportunities.
Solution: Implement certificate transparency validation alongside pinning for defense in depth.
Advanced Considerations
Dynamic Pinning
For advanced use cases, consider dynamic pin updates:
- Fetch updated pins from secure API endpoint
- Implement secure pin update mechanism with signature verification
- Use as fallback for emergency certificate rotation
- Requires careful security design to prevent attacks
Certificate Transparency Integration
Enhance security by validating certificates against CT logs:
- Verify certificates are logged in public CT logs
- Detect mis-issued certificates quickly
- Combine with pinning for comprehensive validation
- Use libraries like TrustKit that support CT validation
Compliance Considerations
Certificate pinning may be required by:
- Financial services regulations (PSD2, PCI DSS)
- Healthcare compliance (HIPAA)
- Government security standards
- Industry-specific security requirements
Conclusion
SSL certificate pinning is a powerful security technique that significantly reduces the risk of man-in-the-middle attacks in mobile applications. When implemented correctly with proper backup pins, rotation procedures, and comprehensive testing, certificate pinning provides an essential additional layer of security for applications handling sensitive data.
The key to successful certificate pinning lies in careful planning, thorough testing, and operational discipline. Always include backup pins, develop clear rotation procedures, and monitor pinning behavior in production. With these practices in place, certificate pinning becomes a manageable and highly effective security control.
As mobile security threats continue to evolve in 2025, certificate pinning remains a critical defense mechanism for protecting user data and maintaining trust in mobile applications.
🔧 SSL Pinning Tools
Use our tools to help with certificate pinning: