API Security Certificate Pinning and Man in the Middle Attacks
Even when HTTPS is correctly implemented, a sophisticated attacker can position themselves between a client and server to intercept and read encrypted traffic. This is called a Man-in-the-Middle (MitM) attack. Certificate pinning is the technique used by mobile apps and other clients to detect and reject these interceptions.
How a Man-in-the-Middle Attack Works
Normal HTTPS Connection:
Mobile App ──────────────────────────────────→ api.bank.com
Encrypted with bank.com's certificate
MitM Attack:
Mobile App → Attacker's Proxy → api.bank.com
↑ ↑
Attacker's cert Bank's cert
(app encrypts to (proxy encrypts
attacker) to real server)
The attacker presents their own TLS certificate to the app.
The proxy decrypts traffic from the app, reads it, then
re-encrypts and forwards it to the real server.
The app thinks it is talking to bank.com.
The server thinks it is talking to the app.
The attacker reads everything in the middle.
Why Normal TLS Does Not Always Stop MitM
Standard TLS validates:
✓ Certificate is signed by a trusted CA
✓ Certificate domain matches the server domain
✓ Certificate is not expired
✓ Certificate is not revoked
The problem: Trusted CAs can issue certificates for any domain.
If an attacker can:
a) Install their own CA certificate on the victim's device (common in
corporate environments, parental control software, or through malware)
b) Compromise or impersonate a legitimate CA (happened with DigiNotar 2011)
c) Purchase a fraudulent certificate for the target domain
Then their MitM certificate passes ALL standard TLS checks.
The device trusts the attacker's certificate.
TLS appears valid. The connection is compromised.
Real-World MitM Scenarios
Scenario 1 — Corporate Network Inspection: Company installs a network appliance that intercepts all HTTPS traffic. The company's CA certificate is installed on all employee devices. All TLS traffic is decrypted at the appliance for monitoring. This is a legitimate MitM — employees should be aware of this policy. Scenario 2 — Mobile App Testing (Burp Suite): Security testers install Burp Suite's CA certificate on a test phone. Burp intercepts all HTTPS calls from the test app. Tester can see all API requests and responses in plain text. This is standard penetration testing methodology. Scenario 3 — Malicious Public WiFi: Attacker sets up a fake "Free_Airport_WiFi" hotspot. Victim's phone connects to it. Attacker's device is the network router. For non-pinned apps, attacker can install their cert and intercept traffic. Scenario 4 — Compromised CA (DigiNotar, 2011): Dutch CA DigiNotar was breached by attackers. Attackers issued fraudulent certificates for google.com, gmail.com, and other major domains — all signed by a trusted CA. Standard TLS checks passed. Users had no indication of interception. DigiNotar was subsequently removed from trusted CA lists and went bankrupt.
What Is Certificate Pinning
Certificate pinning is a technique where the client application hardcodes which specific certificate or public key it will accept from the server. If the server presents any other certificate — even one signed by a trusted CA — the connection is refused.
Without Pinning: App receives certificate for api.bank.com signed by TrustyCorp CA. App checks: "Is TrustyCorp CA in my trusted CA list?" Yes. App accepts the certificate and connects. → Works for legitimate server AND for attacker's proxy with TrustyCorp cert. With Certificate Pinning: App has hardcoded: "api.bank.com's certificate fingerprint is SHA256:abc123..." App receives certificate. App checks: "Does this certificate's fingerprint match abc123...?" Legitimate server: Yes → Connect. Attacker's proxy: No → Connection refused. "Certificate mismatch."
Two Types of Pinning
Type 1: Certificate Pinning
Pin the entire certificate (all fields).
Most restrictive.
Problem: When the certificate expires and is renewed, the fingerprint
changes. The app breaks until updated with new certificate.
Use case: Very high security apps where cert changes are coordinated.
Type 2: Public Key Pinning (Recommended)
Pin only the server's public key (not the whole certificate).
The public key can remain the same across certificate renewals
if the same key pair is reused or if backup pins are maintained.
More resilient to routine certificate renewal.
Public key pin value:
sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=
(SHA-256 hash of the SubjectPublicKeyInfo from the certificate)
Implementing Pinning in Mobile Apps
Android — OkHttp (Java/Kotlin):
OkHttpClient client = new OkHttpClient.Builder()
.certificatePinner(new CertificatePinner.Builder()
.add("api.bank.com", "sha256/AAAA...") // Primary pin
.add("api.bank.com", "sha256/BBBB...") // Backup pin
.build())
.build();
iOS — URLSession with custom delegate:
func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverCert = challenge.protectionSpace.serverTrust,
let publicKey = extractPublicKey(serverCert),
publicKey == expectedPublicKeyHash else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
completionHandler(.useCredential, URLCredential(trust: serverCert))
}
Flutter — dio package with custom interceptor:
Implement in the HTTP client to validate against pinned hash.
React Native — react-native-ssl-pinning library:
fetch('https://api.bank.com/data', {
sslPinning: {
certs: ['cert_hash_here']
}
});
Backup Pins — Critical for Production
Always define at least TWO pins: Pin 1: Current certificate's public key (active) Pin 2: Next certificate's public key (prepared in advance) OR Pin 2: Intermediate CA's public key (broader coverage) Why backup pins matter: If only one pin and the certificate is compromised or needs emergency replacement — all users with the old app version cannot connect. The app becomes completely non-functional until users update. Certificate Rotation Process with Backup Pins: 1. Generate new key pair and certificate (new_cert) 2. Add new_cert's public key as Pin 2 (backup) in next app release 3. Deploy new app version (now pinned to both old and new certs) 4. When most users have updated, swap the server certificate to new_cert 5. Remove old pin in subsequent app release
Pinning Bypass Techniques and Defenses
Attackers and security testers attempt to bypass pinning using: Bypass 1: Frida (Dynamic Instrumentation) Frida hooks into the running app process. Overrides the pinning validation function to always return "match". Defense: Runtime Application Self-Protection (RASP) Detect if Frida or debuggers are attached. Refuse to run if tampering is detected. Bypass 2: Repackaging the APK Attacker decompiles the Android APK. Removes or modifies the pinning code. Recompiles and installs the modified APK. Defense: Implement APK integrity checking. Verify the app's own signature has not changed. Use Play Integrity API (Android) or DeviceCheck (iOS). Bypass 3: Custom ROM / Rooted Device Rooted Android or jailbroken iOS can manipulate TLS stack. Defense: Check for root/jailbreak at app startup. Refuse to process sensitive data on rooted devices. Bypass 4: Intercepting at Build Time Attacker has access to build environment. Modifies pinning configuration before app is compiled. Defense: Secure build pipeline with access controls and code signing to verify builds are unmodified.
HPKP — The Deprecated Browser Pinning Standard
HTTP Public Key Pinning (HPKP) was a browser-based pinning mechanism where servers could send a header specifying which public keys to pin. Header: Public-Key-Pins: pin-sha256="ABC..."; max-age=5184000; includeSubDomains Why HPKP was deprecated (2018): A misconfigured HPKP header with a wrong pin rendered the entire website inaccessible for the pin's max-age period. Attackers also used it for "hostile pinning" — adding their own key to lock users to their MitM proxy. Current status: Removed from Chrome. Not recommended anywhere. Alternative: Certificate Transparency + CAA DNS records.
Certificate Transparency
Certificate Transparency (CT) is a public audit log of all certificates
issued by Certificate Authorities.
How it helps:
Every publicly trusted certificate must be logged in CT.
Anyone can monitor CT logs for unauthorized certificates
issued for their domain.
If an attacker convinces a CA to issue a certificate for api.bank.com,
that certificate appears in CT logs within seconds.
Bank's monitoring system detects the unauthorized cert and alerts.
Tools:
crt.sh → Search CT logs for any domain's certificates
Facebook CT Monitor → Monitors and alerts on new certificates
Google Certificate Transparency → ct.googleapis.com
Supplementary control:
CAA DNS records specify which CAs are allowed to issue certificates
for your domain. Other CAs should refuse issuance.
dig api.company.com CAA
→ company.com. CAA 0 issue "letsencrypt.org"
(Only Let's Encrypt may issue certs for this domain)
Key Points
- A MitM attack positions an attacker between the client and server, allowing them to decrypt and read HTTPS traffic using their own certificate.
- Standard TLS validation can be defeated if the attacker has a certificate from any trusted CA, or if a trusted CA is compromised.
- Certificate pinning tells the client to only accept a specific certificate or public key from the server, rejecting all others including attacker-controlled ones.
- Public key pinning is preferred over certificate pinning because the key can stay the same across certificate renewals.
- Always implement backup pins to prevent app lockout during certificate rotation.
- Certificate Transparency logs provide early warning when unauthorized certificates are issued for your domain.
