Keychain — este un depozit securizat de date de autentificare în iOS, watchOS, macOS și tvOS, care gestionează parole, chei și certificate la nivel hardware. Spre deosebire de UserDefaults, datele din Keychain sunt criptate și izolate prin sandbox-ul aplicației. Conform Apple Developer Documentation, Keychain utilizează mecanismele Secure Enclave și criptarea hardware AES-256 pentru protejarea informațiilor confidențiale.
Principalele puncte
Keychain — este o bază de date securizată a sistemului de operare Apple, destinată stocării sigure a parolelor, cheilor criptografice, certificatelor și altor date confidențiale. Keychain a apărut pentru prima dată în Mac OS 8.6 în 1999, iar pe iOS — din prima versiune a SDK-ului.
Keychain rezolvă o problemă fundamentală a dezvoltării mobile: stocarea secretelor (token-uri, parole, chei de criptare) în sistemul de fișiere neprotejat. Spre deosebire de UserDefaults sau SQLite, datele din Keychain sunt stocate în formă criptată și se criptează automat la scrierea pe disc.
Fiecare aplicație iOS funcționează într-un sandbox izolat și are acces doar la propriul keychain. Cu toate acestea, dezvoltatorul poate configura accesul partajat la Keychain între aplicațiile aceluiași dezvoltator prin keychain access groups. Utilizatorul iCloud Keychain sincronizează suplimentar datele între dispozitive prin criptare end-to-end.
Conform Apple Security White Paper (2025), Keychain utilizează criptarea hardware AES-256 cu o cheie legată de identificatorul unic al dispozitivului (UID), ceea ce face datele inaccesibile la extragerea din dispozitiv.
Keychain funcționează ca un serviciu pe niveluri: aplicația apelează Security framework, care interacționează cu demonul securityd, ce gestionează baza de date criptată SQLite a Keychain. Fiecare înregistrare este criptată cu o cheie separată, iar cheile în sine sunt protejate de modulul hardware Secure Enclave pe dispozitivele cu cip A7 și mai noi.
Security framework oferă o interfață C pentru lucrul cu Keychain Services. Funcțiile principale: SecItemAdd (adăugare), SecItemCopyMatching (căutare), SecItemUpdate (actualizare) și SecItemDelete (ștergere). Fiecare operație primește un dicționar de atribute CFDictionaryRef care descrie tipul cererii.
Datele sunt clasificate după clase: kSecClassGenericPassword (parolă arbitrară), kSecClassInternetPassword (parolă pentru serviciu internet), kSecClassCertificate (certificat), kSecClassKey (cheie criptografică) și kSecClassIdentity (combinație cheie și certificat).
La salvarea parolei, aplicația formează un dicționar cu atribute: serviciu, cont, nivel de acces, etichetă. Security framework transmite datele demonului securityd, care criptează înregistrarea cu o cheie legată de dispozitiv și o salvează în Keychain SQLite. Extragerea are loc similar: cerere după atribute, căutare, decriptare și returnare a datelor.
O caracteristică importantă: la ștergerea aplicației, iOS curăță automat Keychain de înregistrările create de această aplicație (din iOS 10.3+). La reinstalarea aplicației, datele Keychain din instalarea anterioară sunt inaccesibile, dacă nu s-a folosit iCloud Keychain.
import Security
func savePassword(service: String, account: String, password: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecValueData as String: password,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked
]
SecItemAdd(query as CFDictionary, nil)
}
Keychain suportă cinci clase principale de date, fiecare având propriul set de atribute și domeniu de aplicare. De alegerea clasei depinde ce chei de căutare sunt disponibile și cum sunt criptate datele.
Clasele kSecClassGenericPassword și kSecClassInternetPassword sunt destinate stocării parolelor text. Versiunea internet stochează suplimentar datele serverului: domeniu, protocol, port și cale de autentificare. GenericPassword este folosit pentru stocarea oricăror parole fără legătură cu un server.
La salvarea parolei de internet se pot specifica kSecAttrServer (domeniu), kSecAttrProtocol (HTTPS, FTP etc.), kSecAttrPort și kSecAttrPath. Acest lucru permite identificarea precisă a înregistrării la completarea automată prin AutoFill.
Clasa kSecClassKey stochează chei simetrice (AES) și asimetrice (RSA, EC). Clasa kSecClassCertificate — certificate X.509. Clasa kSecClassIdentity combină cheia privată și certificatul corespunzător într-o singură înregistrare.
Pentru cheile asimetrice, Keychain suportă atributele: kSecAttrKeyType (RSA, EC), kSecAttrKeySizeInBits (2048, 256), kSecAttrIsPermanent (dacă se salvează în Keychain). Pentru certificate: kSecAttrLabel (nume lizibil pentru om), kSecAttrSubject (DN al proprietarului), kSecAttrIssuer (DN al emitentului).
| Clasa Keychain | Destinație | Tip de date |
|---|---|---|
| kSecClassGenericPassword | Parolă aplicație | Data (NSString) |
| kSecClassInternetPassword | Parolă server | Data + atribute server |
| kSecClassCertificate | Certificat X.509 | SecCertificate |
| kSecClassKey | Cheie criptografică | SecKey |
| kSecClassIdentity | Cheie + certificat | SecIdentity |
Interfața principală de interacțiune cu Keychain în codul nativ iOS — funcțiile Security framework. Pentru Swift și Objective-C este disponibilă o interfață C, împachetată în funcții convenabile.
Funcția SecItemAdd adaugă un element nou în Keychain. La intrare primește un dicționar cu clasa, datele și atributele. Returnează statusul errSecSuccess (0) sau un cod de eroare. Funcția SecItemCopyMatching execută căutarea după atribute și returnează datele găsite.
Pentru căutare se folosește flagul kSecReturnData — dacă este true, funcția returnează conținutul înregistrării. Flagul kSecMatchLimit determină numărul de rezultate: kSecMatchLimitOne (unul) sau kSecMatchLimitAll (toate).
func readPassword(service: String, account: String) -> Data? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account,
kSecReturnData as String: true,
kSecMatchLimit as String: kSecMatchLimitOne
]
var item: CFTypeRef?
let status = SecItemCopyMatching(query as CFDictionary, &item)
guard status == errSecSuccess else { return nil }
return item as? Data
}
SecItemUpdate permite modificarea atributelor sau datelor unei înregistrări existente. SecItemDelete șterge toate înregistrările corespunzătoare dicționarului transmis. La ștergere este important să se specifice suficiente atribute pentru a nu șterge accidental înregistrări ale altora în shared keychain.
func deletePassword(service: String, account: String) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: service,
kSecAttrAccount as String: account
]
SecItemDelete(query as CFDictionary)
}
Fiecare înregistrare Keychain are atributul kSecAttrAccessible, care determină când datele sunt disponibile pentru citire. Acest lucru este critic pentru securitate: un nivel de acces greșit poate face datele vulnerabile sau, dimpotrivă, inaccesibile în momentul necesar.
kSecAttrAccessibleWhenUnlocked — datele sunt disponibile doar când dispozitivul este deblocat. kSecAttrAccessibleAfterFirstUnlock — disponibile după prima deblocare după repornire. kSecAttrAccessibleAlways — disponibile întotdeauna (nerecomandat). Postfixul ThisDeviceOnly interzice transferul datelor prin backup.
Pe dispozitivele cu Secure Enclave, cheia de criptare Keychain poate fi suplimentar protejată prin biometrie: kSecAccessControlBiometryCurrentSet sau kSecAccessControlUserPresence. Acest lucru adaugă cerința Face ID sau Touch ID pentru fiecare operație de citire.
iCloud Keychain sincronizează înregistrările între dispozitivele Apple prin criptare end-to-end. Apple nu are acces la datele decriptate. Pentru activarea sincronizării, adăugați atributul kSecAttrSynchronizable cu valoarea kCFBooleanTrue.
Important: înregistrările sincronizate nu pot conține atributul ThisDeviceOnly, deoarece trebuie să fie disponibile pe alte dispozitive. La pierderea tuturor dispozitivelor, iCloud Keychain se restabilește printr-un cod de recuperare sau o cheie de rezervă iCloud.
Pentru token-urile de autentificare folosiți kSecAttrAccessibleWhenUnlockedThisDeviceOnly — datele sunt disponibile doar la dispozitivul deblocat și nu se copiază în backup. Pentru certificatele care trebuie să fie disponibile sarcinilor de fundal, folosiți kSecAttrAccessibleAfterFirstUnlock. Nu folosiți niciodată kSecAttrAccessibleAlways pentru date confidențiale.
Se recomandă să adăugați întotdeauna postfixul ThisDeviceOnly pentru datele care nu necesită sincronizare. Acest lucru previne copierea accidentală a secretelor în iCloud sau iTunes backup, de unde pot fi extrase cu instrumente de analiză. Pentru datele critice, combinați disponibilitatea cu kSecAccessControlUserPresence — acest lucru adaugă cerința de biometrie sau cod pentru decriptarea înregistrării.
La utilizarea iCloud Keychain rețineți că înregistrările sincronizate sunt disponibile pe toate dispozitivele utilizatorului: dacă un atacator obține acces la un dispozitiv, datele pot fi compromise pe toate. Pentru secrete izolate, folosiți ThisDeviceOnly.
Întrebări frecvente
UserDefaults stochează datele în formă deschisă în fișierul .plist, accesibil la analiza IPA. Keychain criptează fiecare înregistrare separat, utilizează criptare hardware și suportă niveluri de acces, biometrie și sincronizare prin iCloud.
La fiecare pornire pe simulatorul iOS, Keychain se curăță. Pe dispozitiv real, ștergeți aplicația — iOS va șterge toate înregistrările Keychain ale acestui dezvoltator. Pentru curățarea selectivă, apelați SecItemDelete cu atributele corespunzătoare.
Da, prin keychain access groups. Aplicațiile trebuie să aibă același team ID în semnătură și entitlements cu același keychain-access-groups. Dezvoltatorul configurează accesul partajat în Xcode Capabilities.
Apple nu documentează o limită strictă, dar în practică se recomandă să nu se depășească 1–4 KB per înregistrare. Pentru volume mari, folosiți criptarea fișierelor și stocarea cheii în Keychain, iar datele în sine — în Documents.
La jailbreak, protecția Keychain se reduce, deoarece atacatorul obține acces root și poate citi Keychain SQLite direct. Pentru date critice, folosiți criptare suplimentară cu o cheie obținută de pe server.
Rezumat
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