Certificate Pinning — mecanism de fixare a certificatului sau a cheii publice a serverului, prin care aplicația folosește o amprentă cunoscută dinainte pentru verificarea conexiunii HTTPS. Spre deosebire de lanțul standard de încredere prin CA, pinning garantează că nici măcar o autoritate de certificare compromisă nu poate emite un certificat fals pentru domeniul dumneavoastră. Conform OWASP MSTG (2025), Certificate Pinning face parte din lista controalelor obligatorii pentru aplicațiile cu nivel de protecție L2. Implementarea include stocarea hashurilor certificatelor în cod și verificarea la fiecare cerere.
Elemente principale
Certificate Pinning — este o tehnică de securitate prin care aplicația stochează amprenta (fingerprint) unui certificat de încredere și o folosește ca unic criteriu pentru stabilirea conexiunii HTTPS. În modelul standard TLS, clientul verifică dacă certificatul serverului este semnat de o autoritate CA rădăcină de încredere — oricare dintre sutele de autorități preinstalate în sistem. Certificate Pinning înlocuiește acest lanț cu o verificare directă: certificatul trebuie să coincidă cu eșantionul stocat sau să conțină cheia publică așteptată.
Problema modelului standard a devenit evidentă după incidentele de compromitere a CA — DigiNotar (2011), Comodo (2011), TrustCor (2022). Dacă un CA emite un certificat fals pentru domeniul dumneavoastră, browserul sau aplicația îl acceptă ca valid. Certificate Pinning previne acest atac: chiar și un certificat fals perfect semnat va fi respins, deoarece amprenta sa nu coincide cu cea fixată în aplicație.
Termenul pinning provine de la pin — „ac de fixare“: dezvoltatorul fixează certificatul de încredere, iar orice abatere de la acesta blochează conexiunea. Conform cercetării Mitre CWE-295, validarea incorectă a certificatelor rămâne una dintre primele 10 cele mai periculoase erori de securitate în aplicațiile mobile, iar Certificate Pinning este metoda directă de prevenire a acesteia.
Inițial, Certificate Pinning era utilizat în browsere prin mecanismul HPKP (HTTP Public Key Pinning), standardizat în RFC 7469. Dezvoltatorul trimitea un antet HTTP Public-Key-Pins cu hashurile cheilor așteptate, iar browserul le reținea pentru o perioadă specificată. Cu toate acestea, HPKP s-a dovedit periculos: o singură eroare de configurare putea bloca site-ul pentru luni întregi. În 2018, Chrome a întrerupt suportul pentru HPKP, iar acum standardul este implementarea software de partea clientului — în interiorul aplicației mobile sau al extensiei de browser.
Procesul Certificate Pinning include trei etape cheie: calcularea amprentei, verificarea la conectare și gestionarea erorii. În etapa de pregătire, dezvoltatorul obține hashul SHA-256 al certificatului sau al cheii publice a serverului de producție. Pentru aplicațiile conforme cu GDPR și PCI DSS, este necesară și fixarea amprentelor CA-urilor intermediare din lanț.
La fiecare cerere HTTPS, aplicația interceptează callback-ul de autentificare TLS, extrage certificatul serverului și calculează hashul său SHA-256. Acest hash este comparat cu lista stocată de amprente de încredere. Dacă se găsește o potrivire — conexiunea continuă. Dacă nu — aplicația trebuie să întrerupă conexiunea și să raporteze eroarea, fără a dezvălui detalii de implementare atacatorului.
fun validateCertificate(certificate: X509Certificate,
expectedHash: String): Boolean {
val digest = MessageDigest.getInstance("SHA-256")
val hash = Base64.encodeToString(
digest.digest(certificate.publicKey.getEncoded()),
Base64.DEFAULT
).trim()
return hash == expectedHash
}
Funcția primește un obiect X509Certificate de la server și hashul așteptat. Mai întâi se extrage cheia publică a certificatului, se calculează hashul SHA-256 și se codifică în Base64. Rezultatul se compară cu amprenta așteptată. În producție, merită adăugată verificarea pe un array de 2–3 amprente pentru a susține rotația.
La implementarea pinning-ului, trebuie ales care obiect criptografic va fi fixat. Certificate Pinning se leagă de certificatul X.509 în sine — numărul său de serie, perioada de valabilitate și întregul lanț. Public Key Pinning fixează doar cheia publică din interiorul certificatului, ignorând celelalte câmpuri. Alegerea influențează semnificativ costurile operaționale.
| Criteriu | Certificate Pinning | Public Key Pinning |
|---|---|---|
| Obiectul fixării | Certificatul X.509 în întregime | Cheia publică RSA/ECDSA |
| Rotație | Necesită actualizare la fiecare reemitere | Nu se schimbă la modificarea certificatului cu aceeași cheie |
| Securitate | Fixare maxim precisă | Mai puțin sensibil la detalii |
| Flexibilitate | Scăzută — certificatele se schimbă la 1–2 ani | Ridicată — cheile pot trăi 5–10 ani |
| Recomandare | Pentru sisteme critice cu actualizări controlate | Pentru majoritatea aplicațiilor mobile și API-urilor |
Public Key Pinning — alegerea preferată pentru majoritatea proiectelor. Cheile publice ale serverelor rămân de obicei neschimbate la reemiterea certificatului — compania semnează pur și simplu cheia veche cu un certificat nou. Aceasta înseamnă că aplicația nu necesită actualizare după schimbarea certificatului, dacă perechea de chei nu s-a modificat. Certificate Pinning este recomandat pentru scenariile în care dezvoltatorul controlează complet atât serverul, cât și codul client, de exemplu, în aplicațiile corporative cu un ciclu strict de actualizare.
TOFU — strategie în care Certificate Pinning nu este configurat dinainte, ci reține certificatul la prima conexiune cu serverul. Această abordare este convenabilă pentru aplicațiile care nu știu dinainte la ce server se vor conecta. Dezavantajul — vulnerabilitatea la primul atac: dacă prima conexiune este interceptată, certificatul fals va fi acceptat ca de încredere. TOFU se aplică în conexiunile SSH și în unele protocoale P2P.
Pe ambele platforme, Certificate Pinning se implementează prin interceptarea conexiunii TLS la nivelul stivei de rețea. Pe iOS se utilizează delegatul URLSession sau Alamofire ServerTrustManager. Pe Android, metoda preferată este OkHttp CertificatePinner, care este integrat în clienții HTTP populari și suportă configurarea mai multor amprente pentru fiecare domeniu.
func validate(serverTrust: SecTrust,
pinnedHash: String) -> Bool {
guard let certificates = SecTrustCopyCertificateChain(serverTrust)
as? [SecCertificate] else { return false }
for certificate in certificates {
let data = SecCertificateCopyData(certificate)
var hash = Data(repeating: 0, count: Int(CC_SHA256_DIGEST_LENGTH))
data.withUnsafeBytes {
CC_SHA256($0.baseAddress,
CC_LONG(data.count), &hash)
}
if hash.base64EncodedString() == pinnedHash {
return true
}
}
return false
}
În funcția Swift, din serverTrust se extrage lanțul de certificate, pentru fiecare se calculează hashul SHA-256, iar rezultatul se compară cu cel așteptat. Parcurgerea tuturor certificatelor din lanț permite implementarea pinning-ului la nivelul CA-ului intermediar — dacă certificatul intermediar se potrivește, conexiunea este acceptată. Aceasta oferă flexibilitate la rotația certificatelor leaf.
Dacă aplicația nu folosește OkHttp, Certificate Pinning poate fi implementat printr-un X509TrustManager personalizat. Această metodă necesită mai mult cod, dar oferă control complet asupra procesului de verificare. TrustManager suprascrie metoda checkServerTrusted, unde dezvoltatorul verifică manual certificatele serverului și ia decizia de încredere. Recomandat doar pentru scenarii specifice în care biblioteca OkHttp nu este disponibilă.
Cea mai frecventă greșeală — lipsa pinurilor de rezervă. Dezvoltatorul plasează o singură amprentă a certificatului, iar la expirarea acestuia utilizatorii pierd în masă conexiunea. Configurația minim acceptabilă — două amprente: certificatul curent și cel de rezervă. Optim — trei: curent, de rezervă și amprenta CA-ului rădăcină ca fallback.
A doua greșeală — stocarea pinurilor în formă deschisă în cod. Un atacator cu acces la APK sau IPA poate extrage și înlocui cu ușurință amprentele. Se recomandă ofuscarea hashurilor: împărțirea șirului în părți, stocarea în resurse criptate sau calcularea prin runtime. Pentru Android, ProGuard cu ofuscarea constantelor șir este eficient.
A treia greșeală — pinning la nivelul certificatului de dezvoltare. Certificatele de dezvoltare și producție sunt de obicei diferite, dar dezvoltatorii uită adesea să schimbe pinurile la construirea versiunii de release. Rezultatul — aplicația de producție nu se poate conecta la server. Soluția — configurație separată a pinurilor pentru debug și release prin BuildConfig sau resurse specifice flavour-ului.
Întrebări frecvente
SSL Pinning — termen general pentru legarea de un certificat SSL/TLS. Certificate Pinning — o implementare concretă care fixează certificatul X.509 în sine, nu doar cheia publică. Diferența constă în obiectul fixării: certificat vs cheie.
Se recomandă stocarea hashurilor în resurse cu ofuscare prin ProGuard (Android) sau criptate prin Keychain (iOS). Evitați stocarea pinurilor în formă deschisă în strings.xml sau Info.plist fără criptare.
La fiecare schimbare a certificatului pe server. Se recomandă adăugarea unei noi amprente ca pin de rezervă cu 3–6 luni înainte de expirarea celei curente, iar după rotație ștergerea celei vechi. Cel puțin un pin de rezervă este obligatoriu.
Da, prin compilare condiționată: în build-ul de debug pinning este dezactivat, în release — activat. Folosiți BuildConfig.DEBUG pe Android sau #if DEBUG pe iOS pentru comutare. Nu faceți niciodată acest lucru printr-un flag de runtime accesibil utilizatorului.
Lansați imediat o actualizare a aplicației cu noile amprente și publicați-o în magazine. Folosiți un mecanism de actualizare forțată. Dacă pinurile de rezervă includeau amprenta CA-ului de rezervă, temporar se poate trece la un alt domeniu cu un alt certificat.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și