Civiele & structurele engineering
De implementatie van beveiligde gegevensopslag met de sleutelhanger in Ios
Table of Contents
Inleiding tot beveiligde gegevensopslag op iOS
Het beschermen van gevoelige gebruikersgegevens is een fundamentele verantwoordelijkheid van elke iOS-applicatie. Of u nu authenticatie tokens, encryptiesleutels of persoonlijke referenties opslaat, het platform biedt een speciale hardware-backed oplossing: de Keychain. In tegenstelling tot of eigendomslijst bestanden, de Keychain versleutelt gegevens in rust en verplicht strikte toegangscontrole. Dit artikel biedt een uitgebreide gids voor het implementeren van veilige gegevensopslag met de Keychain, die zowel de native Security kader en praktische beste praktijken voor productie-apps.
Begrijpen van de iOS-sleutelhanger
De Keychain is een veilige opslag container beheerd door het besturingssysteem. Het slaat kleine, gevoelige items . zoals wachtwoorden, cryptische sleutels, of certificaten . In een gecodeerde database . Gegevens geschreven naar de Keychain is beschermd, zelfs wanneer het apparaat is vergrendeld . Belangrijkste mogelijkheden zijn:
- Versleuteling in rust met behulp van hardware-backed AES-256.
- Toegangscontrole via apparaatpascode, Touch ID of gezichts-ID.
- Persisentie over app-herinstalleert (indien geconfigureerd) en optionele iCloud-synchronisatie.
- Isolatie tussen apps: standaard kan een app geen andere apps lezen Sleutelhangers tenzij ze een toegangsgroep voor sleutelhangers delen.
De Keychain is niet ontworpen voor grote blobs; houd elk item onder een paar kilobytes. Voor grotere gegevens, overwegen het gebruik van de API of het kader samen met bestandsgebaseerde encryptie.
Sleutelhangersservice API vs. Bibliotheken van derden
Apple levert de oorspronkelijke Keychain Services API (C-based, ), die krachtig is maar verbose. Je kunt het direct gebruiken, of een Swift-vriendelijke wikkel aannemen. Populaire bibliotheken van derden zoals KeychainAccess of SwiftKeychainWrapper[] verminderen ketelplaat. Echter, begrijpen van de onderliggende API is essentieel voor het debuggen en wanneer je fijnkorrelige controle over toegangsbeleid nodig hebt. Vandaag zullen we ons richten op de oorspronkelijke API met Swift.
Het instellen van sleutelhanger opslag
Voordat je iets opslaat, moet je beslissen over de Keychain item klasse. De meest voorkomende voor generische wachtwoorden is . Voor Internet wachtwoorden of certificaten zijn er andere klassen. Elk item wordt verwezen door een set attributen een woordenboek (CFDctionary) dat het item beschrijft.
De basisstroom volgt altijd dit patroon:
- Bouw een zoekwoordenboek met de itemklasse en attributen.
- Noem de relevante -functie (, , , ).
- Controleer de geretourneerde ( of een foutcode).
Voor het schrijven van code, importeer de Security module:
import Security
import Foundation // for Data and String utilities
Gegevens opslaan in de sleutelhanger
Een generiek wachtwoord schrijven
Om een token (bv. een JWT) voor de huidige gebruiker op te slaan:
func saveToken(_ token: String, forAccount account: String) -> Bool {
guard let tokenData = token.data(using: .utf8) else { return false }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecValueData as String: tokenData,
// Optional: restrict access to when device is unlocked
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
// Delete any existing item first to avoid duplicates
SecItemDelete(query as CFDictionary)
let status = SecItemAdd(query as CFDictionary, nil)
return status == errSecSuccess
}
Belangrijkste punten:
- fungeert als primaire sleutel; kies een unieke string (bv. de gebruikers-ID of een constante als ).
- stuurt wanneer het item gelezen kan worden. Gebruik voor de beste beveiliging; het voorkomt iCloud back-up en beperkt de toegang tot het huidige apparaat.
- We roepen op voordat we toevoegen om te voorkomen dat er dubbele items worden verzameld. Als alternatief kunt u gebruiken.
Toegangscontrole toevoegen (Biometrie of Passcode)
Voor zeer gevoelige gegevens, moet u Touch ID of Face ID voor het lezen:
let accessControl = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
.userPresence, // requires passcode, Face ID, or Touch ID
nil
)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account,
kSecValueData as String: tokenData,
kSecAttrAccessControl as String: accessControl as Any
]
SecItemAdd(query as CFDictionary, nil)
Nu zal een oproep voor dit item een biometrische of wachtwoordprompt activeren. Gebruik vanuit LocalAuthentication om de interactie van de gebruiker sierlijk te behandelen.
Gegevens uit de sleutelhanger ophalen
Om het opgeslagen token te lezen:
func retrieveToken(forAccount account: String) -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
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,
let data = item as? Data,
let token = String(data: data, encoding: .utf8) else {
return nil
}
return token
}
Stel in op ] om de gegevens terug te krijgen. Gebruik om één resultaat op te halen. Als u de limiet weglaat, kan de API een array teruggeven.
Belangrijk: Wanneer u toegangscontrole (biometrie) gebruikt, kan de oproep terugkeren als de gebruiker annuleert. Deze zaak apart behandelen en nooit terugvallen op de opslag van platte tekst.
Bijwerken en verwijderen van sleutelhanger items
Een bestaand item bijwerken
Gebruik in plaats van het verwijderen en opnieuw toevoegen :
func updateToken(_ newToken: String, forAccount account: String) -> Bool {
guard let newData = newToken.data(using: .utf8) else { return false }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account
]
let attributesToUpdate: [String: Any] = [
kSecValueData as String: newData
]
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
return status == errSecSuccess
}
Dit is efficiënter dan een delete+add, en het vermijdt potentiële racevoorwaarden.
Een item verwijderen
func deleteItem(forAccount account: String) -> Bool {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: account
]
let status = SecItemDelete(query as CFDictionary)
return status == errSecSuccess
}
Wees voorzichtig om items die behoren tot andere apps delen dezelfde toegang groep niet te verwijderen.Scopeer altijd uw query met als u gedeelde Keychains gebruikt.
Toegangscontrole en toegankelijkheidsattributen
De constante definieert wanneer het sleutelhanger-item gelezen kan worden. Kies de meest beperkende optie die nog steeds aan uw app voldoet.
| Attribute | Meaning |
|---|---|
kSecAttrAccessibleWhenUnlocked | Available only while device is unlocked (default). |
kSecAttrAccessibleAfterFirstUnlock | Available after device boots and is unlocked once. Allows background access. |
kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly | Requires a passcode to be set. Strictest option—prevents access even after unlock if passcode is removed. |
kSecAttrAccessibleWhenUnlockedThisDeviceOnly | Same as WhenUnlocked but does not back up to iCloud, and cannot be restored to another device. |
Voor de meeste apps, , vindt u de juiste balans tussen veiligheid en bruikbaarheid. Als u items op de achtergrond moet lezen (bijvoorbeeld een achtergrondverversings token), moet u gebruiken (en accepteren dat de gegevens iets minder beschermd zijn).
Fout bij het hanteren van en gemeenschappelijke vallen
De functies geven een terug. Controleer het altijd en los fouten op de juiste manier op. Veel voorkomende fouten:
- (
- (
- (
- (
Negeer nooit een niet-successtatus. Op een vriendelijke manier afbreken: toon een foutmelding of probeer het opnieuw, maar sla nooit gevoelige gegevens buiten de Keychain op als een terugval. U kunt [] gebruiken om de biometrische beschikbaarheid te controleren voordat u toegang probeert te verkrijgen.
Beste praktijken en productieoverwegingen
- Gebruik unieke, beschrijvende accountnamen per gebruiker of per itemtype om botsingen te voorkomen.
- Geef altijd een toegankelijkheidsattribuut ; anders is de systeemstandaard () van toepassing, wat misschien niet ideaal is.
- Verwijder sleutelhangergegevens wanneer de gebruiker zich uitlogtVerwijder over alle bekende accounts en verwijder items.
- Gebruik Keychain Access Groups alleen bij het delen tussen uw eigen apps. Vermijd brede groepen.
- Nooit niet-gevoelige gegevens opslaan (zoals gebruikersvoorkeuren) in de Keychain
- Voortgang van de toepassing van met voor geavanceerde scenario's (macOS-katalysatoren).
- Probeer op een echt apparaat; de Simulator gebruikt een software Keychain die zich anders gedraagt dan hardware-backed opslag.
Gebruik van sleutelhanger met SwiftUI en Async/Await
Voor moderne apps, wrap Keychain operaties in een acteur of een async-veilige klasse om te voorkomen dat het blokkeren van de hoofddraad. Voorbeeld met behulp van :
actor KeychainManager {
func saveToken(_ token: String, for account: String) async -> Bool {
// same implementation as above, but now it's safe to call from any context
return saveToken(token, forAccount: account)
}
}
Als u biometrische gegevens gebruikt, kan de -oproep de draad blokkeren in afwachting van de interactie van de gebruiker. Wikkel het in een achtergrondwachtrij, of beter, gebruik ] -methode voor de Keychain-oproep.
Conclusie
The iOS Keychain is the correct place to store small, sensitive pieces of data. By using the native Keychain Services API, you gain direct control over encryption, accessibility, and authentication policies. Always pair your Keychain usage with solid error handling and remember to clear data when appropriate. For further reading, refer to the Apple Keychain Service Documentation and the Keychain Concepts overview. Adopting these practices will help you ship iOS apps that respect user privacy and withstand security scrutiny.