Génie civil & structural
Mise en œuvre du stockage sécurisé des données avec la chaîne-clés en Ios
Table of Contents
Introduction à la sécurisation du stockage des données sur iOS
La protection des données sensibles des utilisateurs est une responsabilité fondamentale de toute application iOS. Que vous stockiez des jetons d'authentification, des clés de chiffrement ou des identifiants privés, la plateforme fournit une solution dédiée au support matériel : Keychain. Contrairement aux fichiers ou des listes de propriétés, la Keychain crypte les données au repos et impose des contrôles d'accès stricts. Cet article fournit un guide complet pour la mise en œuvre du stockage sécurisé des données avec la Keychain, couvrant à la fois le cadre de sécurité natif et les meilleures pratiques pratiques pratiques pour les applications de production.
Comprendre la chaîne-clés iOS
Le Keychain est un conteneur de stockage sécurisé géré par le système d'exploitation. Il stocke des éléments sensibles de petite taille (mots de passe, clés cryptographiques, certificats, etc.) dans une base de données chiffrée. Les données écrites sur le Keychain sont protégées même lorsque l'appareil est verrouillé.
- Encryptage au repos en utilisant AES-256 soutenu par le matériel.
- Contrôle d'accès[ par le code passe, l'ID tactile ou l'ID visage du périphérique.
- La persistance sur l'application réinstalle (si configuré) et la synchronisation optionnelle iCloud.
- Isolation entre les applications : par défaut, une application ne peut pas lire d'autres éléments Keychain d'applications à moins qu'ils ne partagent un groupe d'accès Keychain.
La porte-clés n'est pas conçue pour les gros blobs; conservez chaque élément sous quelques kilooctets. Pour les données plus grandes, envisagez d'utiliser l'API ou le cadre avec le chiffrement basé sur les fichiers.
API des services de porte-clés vs bibliothèques de tiers
Apple fournit l'API native Keychain Services[ API (basée sur C, ), qui est puissante mais verbeuse. Vous pouvez l'utiliser directement, ou adopter un wrapper facile à utiliser. Des bibliothèques tierces populaires comme KeychainAccess ou SwiftKeychainWrapper réduisent la plaque de chaudière. Cependant, comprendre l'API sous-jacente est essentiel pour déboger et quand vous avez besoin d'un contrôle fin sur les politiques d'accès.
Configuration du stockage des porte-clés
Avant de stocker quoi que ce soit, vous devez décider de la classe de l'élément de la chaîne-clé. Le plus courant pour les mots de passe génériques est . Pour les mots de passe ou certificats Internet, il y a d'autres classes. Chaque élément est référencé par un ensemble d'attributs – un dictionnaire (CFDictionary) qui décrit l'élément.
Le flux de base suit toujours ce schéma:
- Construisez un dictionnaire de requêtes avec la classe et les attributs de l'élément.
- Appeler la fonction appropriée (, , , ).
- Cochez le retourné (] ou un code d'erreur).
Avant d'écrire le code, importez le module Sécurité :
import Security
import Foundation // for Data and String utilities
Stockage des données dans la chaîne-clés
Écrire un mot de passe générique
Pour enregistrer un jeton (par exemple, un JWT) pour l'utilisateur actuel :
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
}
Points clés:
- agit comme une clé primaire; choisissez une chaîne unique (p. ex., l'ID de l'utilisateur ou une constante comme .
- contrôle quand l'article peut être lu. Utilisez pour une meilleure sécurité; il empêche la sauvegarde iCloud et restreint l'accès au périphérique actuel.
- Nous appelons avant d'ajouter pour éviter d'accumuler des éléments dupliqués. Vous pouvez également utiliser .
Ajout du contrôle d'accès (biométrie ou code de passe)
Pour les données très sensibles, requirez Touch ID ou Face ID avant de lire:
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)
Maintenant, tout appel pour cet élément déclenchera une invitation biométrique ou de code de passe. Utilisez de LocalAuthentification pour gérer l'interaction utilisateur gracieusement.
Récupération de données à partir de la chaîne-clés
Pour lire le jeton stocké :
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
}
Réglez à pour récupérer les données. Utilisez pour récupérer un seul résultat. Si vous omettez la limite, l'API peut renvoyer un tableau.
Important: Lorsque l'on utilise le contrôle d'accès (biométrie), l'appel peut retourner si l'utilisateur annule.
Mise à jour et suppression des éléments de porte-clés
Mise à jour d'un élément existant
Au lieu de supprimer et de re-addiquer, utiliser :
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
}
Ceci est plus efficace qu'un delete+add, et il évite les conditions de course potentielles.
Suppression d'un élément
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
}
Attention à ne pas supprimer les éléments qui appartiennent à d'autres applications partageant le même groupe d'accès – toujours Agrandir votre requête avec si vous utilisez des Keychains partagés.
Contrôle de l'accès et attributs d'accessibilité
La constante définit quand l'élément Keychain peut être lu. Choisissez l'option la plus restrictive qui répond toujours aux besoins de votre application:
| 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. |
Pour la plupart des applications, établit le bon équilibre entre sécurité et facilité d'utilisation. Si vous devez lire des éléments en arrière-plan (par exemple, un jeton de rafraîchissement de fond), vous devez utiliser (et accepter que les données soient légèrement moins protégées).
Gestion des erreurs et pièges communs
Les fonctions retournent un . Vérifiez toujours et manipulez les défaillances de façon appropriée.
- (–25300) – Aucun élément ne correspond à la requête.
- (–25299) – Un élément avec la même clé primaire existe déjà (si vous n'avez pas supprimé la première).
- (–128] – L'utilisateur a annulé l'invite biométrique.
- (–25293) – L'authentification a échoué ou la biométrie n'est pas disponible.
Ne jamais ignorer un statut de non-réussite. Gracieusement dégradé: afficher un message d'erreur ou de réessayer, mais ne jamais stocker des données sensibles en dehors du Keychain comme un retour. Vous pouvez utiliser pour vérifier la disponibilité biométrique avant de tenter d'accéder.
Meilleures pratiques et considérations relatives à la production
- Utilisez des noms de comptes descriptifs uniques par utilisateur ou par type d'article pour éviter les collisions.
- Veuillez toujours spécifier un attribut d'accessibilité[; sinon, la valeur par défaut du système () s'applique, ce qui peut ne pas être idéal.
- Clarifier les données de la chaîne-clés lorsque l'utilisateur se déconnecte—interdirait sur tous les comptes connus et supprimerait les éléments.
- Utilisez les groupes d'accès à la chaîne-clés uniquement lorsque vous partagez vos propres applications.
- Ne conserve jamais de données non sensibles (comme les préférences de l'utilisateur) dans la chaîne-clés—utilisez ou une base de données à la place.
- Considérer en utilisant avec pour les scénarios avancés (macOS Catalyst).
- Test sur un appareil réel; le Simulator utilise un logiciel Keychain qui se comporte différemment du stockage soutenu par le matériel.
Utilisation de la chaîne-clés avec SwiftUI et Async/Await
Pour les applications modernes, enveloppez les opérations Keychain dans un acteur ou une classe de sécurité async pour éviter de bloquer le thread principal. Exemple en utilisant :
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)
}
}
Si vous utilisez la biométrie, l'appel peut bloquer le thread en attendant l'interaction de l'utilisateur. Enveloppez-le dans une file d'attente de fond, ou mieux, utilisez la méthode S avant l'appel Keychain.
Conclusion
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.