Middle
¿Dónde almacenaría los datos protegidos del usuario?
sobes.tech AI
Respuesta de la IA
Para almacenar datos protegidos del usuario en iOS, utilizaría los siguientes lugares, dependiendo del tipo de datos y del nivel de seguridad:
-
Keychain Services:
- Ideal para almacenar pequeñas cantidades de información confidencial, como contraseñas, tokens de autorización, claves de cifrado.
- El demonio del sistema
securitydgestiona el keychain y almacena los datos cifrados en disco. - Soporta diferentes niveles de accesibilidad (por ejemplo, solo disponible cuando el dispositivo está desbloqueado).
- Los datos se sincronizan automáticamente a través de iCloud Keychain, si está habilitado.
import Foundation import Security func savePassword(service: String, account: String, password: String) -> OSStatus { let data = password.data(using: .utf8)! let query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrService as String: service, kSecAttrAccount as String: account, kSecValueData as String: data ] SecItemDelete(query as CFDictionary) // Eliminamos la entrada existente return SecItemAdd(query as CFDictionary, nil) // Añadimos la nueva entrada } -
Core Data cifrado / Realm:
- Para almacenar datos estructurados que requieren cifrado a nivel de base de datos.
- Core Data soporta extensiones de terceros para cifrado (por ejemplo, RNCryptor).
- Realm Database tiene cifrado de archivos de base de datos incorporado.
- La clave de cifrado debe almacenarse en Keychain.
// Ejemplo de inicialización de Realm con cifrado import RealmSwift func setupEncryptedRealm() throws { var config = Realm.Configuration() if let key = KeychainHelper.getRealmEncryptionKey() { // Obtenemos la clave de Keychain config.encryptionKey = key } else { // Generamos una nueva clave, la almacenamos en Keychain y la usamos let newKey = NSMutableData(length: 64)! _ = SecRandomCopyBytes(kSecRandomDefault, newKey.length, newKey.mutableBytes) KeychainHelper.saveRealmEncryptionKey(key: newKey as Data) config.encryptionKey = newKey as Data } let realm = try Realm(configuration: config) // Usamos Realm } -
APIs de protección de archivos:
- Para cifrar archivos almacenados en el sistema de archivos de la aplicación.
- iOS cifra automáticamente los archivos a nivel del sistema de archivos usando claves gestionadas por Secure Enclave.
- Se pueden establecer diferentes modos de protección (por ejemplo,
complete,completeUnlessOpen,completeUntilFirstUserAuthentication,none) para controlar el acceso según el estado del bloqueo del dispositivo.
func saveProtectedDataToFile(data: Data, fileName: String) throws { let fileManager = FileManager.default let urls = fileManager.urls(for: .documentDirectory, in: .userDomainMask) guard let documentDirectory = urls.first else { throw NSError(domain: "MyApp", code: 1, userInfo: [NSLocalizedDescriptionKey: "Directorio de documentos no encontrado"]) } let fileURL = documentDirectory.appendingPathComponent(fileName) // Establecemos el modo de protección let options: Data.WritingOptions = .atomicWrite let protectedOptions: Data.WritingOptions = options.union(.writingWithoutOverwriting) // Solo un ejemplo, las opciones reales de protección se establecen con atributos del archivo o en info.plist try data.write(to: fileURL, options: options) // Establecer atributos de protección del sistema de archivos (ejemplo) var attributes: [FileAttributeKey : Any] = [:] attributes[.protectionKey] = FileProtectionType.complete try fileManager.setAttributes(attributes, ofItemAtPath: fileURL.path) } -
Secure Enclave:
- Procesador de coprocesador hardware, separado del procesador principal, destinado a almacenar y procesar claves y datos criptográficos.
- Se usa para Touch ID / Face ID y otras operaciones sensibles.
- Las claves almacenadas en Secure Enclave nunca salen de ella y no están disponibles para el procesador principal o el sistema operativo.
- Ideal para generar, almacenar y usar claves para firma o cifrado, donde la protección contra ataques de software es importante.
import CryptoKit import LocalAuthentication func generateAndStoreKeyInSecureEnclave() throws -> P256.Signing.PrivateKey { let accessControl = SecAccessControlCreateWithFlags( kCFAllocatorDefault, kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, // Disponible cuando se establece contraseña [.userPresence], // Requiere autenticación del usuario (Touch ID/Face ID) nil )! let attributes: [String: Any] = [ kSecAttrKeyType as String: kSecAttrKeyTypeECSECPrimeRandom, kSecAttrKeySizeInBits as String: 256, kSecAttrTokenID as String: kSecAttrTokenIDSecureEnclave, kSecPrivateKeyAttrs as String: [ kSecAttrIsPermanent as String: true, // La clave será permanente kSecAttrApplicationTag as String: "com.yourapp.signingkey".data(using: .utf8)!, // Etiqueta única kSecAttrAccessControl as String: accessControl ] ] var error: Unmanaged<CFError>? guard let privateKey = SecKeyCreateRandomKey(attributes as CFDictionary, &error) else { throw error!.takeRetainedValue() as Error } // Se pueden obtener las claves de Secure Enclave por etiqueta para su uso return try P256.Signing.PrivateKey(rawRepresentation: privateKeyData) // Ejemplo, se requiere conversión de SecKey a Data }
La elección del lugar de almacenamiento depende de:
- Tamaño de los datos (pequeño vs datos estructurados).
- Tipo de datos (contraseña vs archivo vs clave criptográfica).
- Nivel de protección requerido.
- Necesidad de sincronización entre dispositivos (Keychain).
- Necesidad de autenticación del usuario para acceder (Secure Enclave, protección de archivos).