Bau- und Bauingenieurwesen
Sichere Datenspeicherung mit dem Schlüsselbund in Ios implementieren
Table of Contents
Einführung in die sichere Datenspeicherung auf iOS
Der Schutz sensibler Benutzerdaten ist eine grundlegende Verantwortung jeder iOS-Anwendung. Ob Sie Authentifizierungstoken, Verschlüsselungsschlüssel oder private Anmeldeinformationen speichern, die Plattform bietet eine dedizierte Hardware-gestützte Lösung: die Keychain Im Gegensatz zu oder Property List Dateien verschlüsselt der Keychain Daten in Ruhe und erzwingt strenge Zugriffskontrollen. Dieser Artikel bietet einen umfassenden Leitfaden zur Implementierung sicherer Datenspeicherung mit dem Keychain, der sowohl das native Sicherheits-Framework als auch praktische Best Practices für Produktions-Apps abdeckt.
Verstehen des iOS Keychain
Der Schlüsselbund ist ein sicherer Speicherbehälter, der vom Betriebssystem verwaltet wird. Er speichert kleine, sensible Elemente wie Passwörter, kryptographische Schlüssel oder Zertifikate in einer verschlüsselten Datenbank. In den Schlüsselbund geschriebene Daten sind auch dann geschützt, wenn das Gerät gesperrt ist.
- Verschlüsselung im Ruhezustand mit Hardware-gestütztem AES-256.
- Zugriffskontrolle über den Gerätepasscode, Touch ID oder Face ID.
- Persistenz über App-Neuinstallationen (falls konfiguriert) und optionale iCloud-Synchronisierung.
- Isolation zwischen Apps: Standardmäßig kann eine App die Schlüsselbundelemente einer anderen App nicht lesen, es sei denn, sie teilen sich eine Schlüsselbund-Zugriffsgruppe.
Der Schlüsselbund ist nicht für große Blobs konzipiert; behalte jedes Element unter wenigen Kilobyte. Für größere Daten solltest du die -API oder das -Framework zusammen mit dateibasierter Verschlüsselung verwenden.
Keychain Services API vs. Bibliotheken von Drittanbietern
Apple stellt die native Keychain Services API (C-basiert, ) zur Verfügung, die leistungsstark, aber ausführlich ist. Sie können sie direkt verwenden oder einen Swift-freundlichen Wrapper übernehmen. Beliebte Bibliotheken von Drittanbietern wie KeychainAccess oder SwiftKeychainWrapper reduzieren das Boilerplate. Das Verständnis der zugrunde liegenden API ist jedoch unerlässlich für das Debuggen und wenn Sie eine feine Kontrolle über Zugriffsrichtlinien benötigen. Heute konzentrieren wir uns auf die native API mit Swift.
Einrichten von Keychain Storage
Bevor Sie etwas speichern, müssen Sie sich für die Schlüsselketten-Elementklasse entscheiden. Die häufigste für generische Passwörter ist . Für Internetpasswörter oder Zertifikate gibt es andere Klassen. Jedes Element wird durch eine Reihe von Attributen referenziert - ein Wörterbuch (CFDictionary), das das Element beschreibt.
Der Grundfluss folgt immer diesem Muster:
- Erstellen Sie ein Abfragewörterbuch mit der Elementklasse und den Attributen.
- Rufen Sie die entsprechende Funktion auf (, , , ).
- Überprüfen Sie die zurückgegebene () oder einen Fehlercode.
Bevor Sie Code schreiben, importieren Sie das Sicherheitsmodul:
import Security
import Foundation // for Data and String utilities
Speichern von Daten im Schlüsselbund
Ein generisches Passwort schreiben
Um ein Token (z. B. ein JWT) für den aktuellen Benutzer zu speichern:
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
}
Schlüsselpunkte:
- fungiert als Primärschlüssel; wählen Sie eine eindeutige Zeichenfolge (z. B. die Benutzer-ID oder eine Konstante wie ).
- steuert, wann das Element gelesen werden kann. Verwenden Sie für beste Sicherheit; es verhindert iCloud-Backup und beschränkt den Zugriff auf das aktuelle Gerät.
- Wir rufen ] auf, bevor wir hinzufügen, um das Ansammeln doppelter Elemente zu vermeiden.
Hinzufügen von Zugriffskontrolle (Biometrie oder Passcode)
Für hochsensible Daten benötigen Sie Touch ID oder Face ID, bevor Sie lesen:
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)
Jetzt wird jeder Aufruf von für dieses Element eine biometrische oder Passcode-Eingabeaufforderung auslösen.
Daten aus dem Keychain abrufen
Um das gespeicherte Token zu lesen:
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
}
Wenn Sie auf setzen, um die Daten zurückzubekommen, verwenden Sie , um ein einzelnes Ergebnis abzurufen.
Wichtig: Bei Verwendung der Zugriffssteuerung (Biometrie) kann der -Aufruf zurückgeben, wenn der Benutzer abbricht.
Aktualisieren und Löschen von Schlüsselbund-Elementen
Aktualisieren eines vorhandenen Elements
Statt zu löschen und erneut hinzuzufügen, verwenden Sie :
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
}
Dies ist effizienter als ein delete + add und vermeidet mögliche Rennbedingungen.
Löschen eines Artikels
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
}
Achten Sie darauf, dass Sie keine Elemente löschen, die zu anderen Apps gehören, die dieselbe Zugriffsgruppe teilen - erweitern Sie Ihre Abfrage immer mit , wenn Sie freigegebene Schlüsselanhänger verwenden.
Access Control und Accessibility Attribute
Die -Konstante definiert , wann das Schlüsselbundelement gelesen werden kann.
| 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. |
Für die meisten Apps findet die richtige Balance zwischen Sicherheit und Benutzerfreundlichkeit.Wenn Sie Elemente im Hintergrund lesen müssen (z. B. ein Hintergrund-Aktualisierungs-Token), müssen Sie verwenden (und akzeptieren, dass die Daten etwas weniger geschützt sind).
Fehlerbehandlung und häufige Fallstricke
Die Funktionen von geben eine zurück.
- (-25300) – Kein Element stimmt mit der Abfrage überein.
- (-25299) – Ein Element mit dem gleichen Primärschlüssel existiert bereits (wenn Sie nicht zuerst gelöscht haben).
- (–128) – Der Benutzer stornierte die biometrische Eingabeaufforderung.
- (–25293) – Authentifizierung fehlgeschlagen oder Biometrie nicht verfügbar.
Anmutig degradieren: eine Fehlermeldung anzeigen oder erneut versuchen, aber niemals sensible Daten außerhalb des Schlüsselbundes als Ausweichmöglichkeit speichern.
Best Practices und Produktionsüberlegungen
- Verwenden Sie eindeutige, beschreibende Kontonamen pro Benutzer oder pro Artikeltyp, um Kollisionen zu vermeiden.
- Spezifizieren Sie immer ein Zugänglichkeitsattribut; andernfalls gilt der Systemstandard (), der möglicherweise nicht ideal ist.
- Keychain-Daten löschen, wenn sich der Benutzer abmeldet—über alle bekannten Konten aufzeichnen und Elemente löschen.
- Verwende Keychain Access Groups nur, wenn du deine eigenen Apps teilst.
- Speichern Sie niemals nicht sensible Daten (wie Benutzerpräferenzen) im Schlüsselbund – verwenden Sie stattdessen oder eine Datenbank.
- Erwägen Sie, mit für fortgeschrittene Szenarien (macOS Catalyst) zu verwenden.
- Test auf einem realen Gerät; der Simulator verwendet eine Software-Schlüsselkette, die sich anders verhält als Hardware-gestützter Speicher.
Verwenden von Keychain mit SwiftUI und Async/Await
Für moderne Apps wickeln Sie Keychain-Operationen in einen Akteur oder eine async-sichere Klasse ein, um das Blockieren des Hauptthreads zu vermeiden.
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)
}
}
Wenn Sie biometrische Daten verwenden, kann der Aufruf den Thread blockieren, während Sie auf die Benutzerinteraktion warten.
Schlussfolgerung
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.