Insecure Keychain Storage
Accesibilidad Insegura de Keychain
Descripción
Keychain es una base de datos especializada para almacenar de forma segura datos sensibles en dispositivos iOS. En Keychain se pueden guardar datos como contraseñas, claves de cifrado o certificados.
Al crear o actualizar un elemento de Keychain, el desarrollador puede determinar las condiciones bajo las cuales se puede acceder utilizando el atributo kSecAttrAccessible. El uso de valores de accesibilidad débiles como kSecAttrAccessibleAlways o kSecAttrAccessibleAlwaysThisDeviceOnly permite que se acceda al elemento de Keychain incluso cuando el dispositivo está bloqueado.
kSecAttrAccessibleAlways y kSecAttrAccessibleAlwaysThisDeviceOnly quedaron obsoletos a partir de iOS 12.0 debido a los riesgos de seguridad. Su uso puede resultar en la exposición de datos sensibles a individuos no autorizados si el dispositivo se pierde, es robado o comprometido.
En los siguientes ejemplos, la especificación incompleta de los indicadores de control de acceso (SecAccessControlCreateFlags) da como resultado un almacenamiento inseguro de los elementos de keychain:
import Foundation
import Security
func saveSecretToKeychain() {
let secretData = "mySecretPassword".data(using: .utf8)!
let access = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleAlways,
.or,
nil
)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecValueData as String: secretData,
kSecAttrAccessControl as String: access!,
]
SecItemAdd(query as CFDictionary, nil)
}
saveSecretToKeychain()
import Foundation
import Security
func saveSecretToKeychain() {
let secretData = "mySecretPassword".data(using: .utf8)!
let access = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleAlways,
.and,
nil
)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecValueData as String: secretData,
kSecAttrAccessControl as String: access!,
]
SecItemAdd(query as CFDictionary, nil)
}
saveSecretToKeychain()
En estos ejemplos, es fundamental especificar correctamente los indicadores de control de acceso para garantizar el almacenamiento seguro de los elementos de keychain. Sin indicadores específicos como kSecAccessControlUserPresence, los elementos de keychain permanecen vulnerables al acceso no autorizado.
Recomendación
Cuando son suficientes los requisitos de control de acceso simples, puede especificar directamente el nivel de accesibilidad utilizando kSecAttrAccessible. La omisión de kSecAttrAccessControl es aceptable en estos casos.
| Caso de Uso | Protección |
|---|---|
| Almacenar datos siempre accesibles | kSecAttrAccessibleAlways |
| Almacenar datos accesibles después del primer desbloqueo | kSecAttrAccessibleAfterFirstUnlock |
| Almacenar datos accesibles solo cuando el dispositivo está desbloqueado | kSecAttrAccessibleWhenUnlocked |
Ejemplo:
import Foundation
import Security
func saveSecretToKeychain() {
let secretData = "mySecretPassword".data(using: .utf8)!
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecValueData as String: secretData,
kSecAttrAccessible as String: kSecAttrAccessibleAlways
]
SecItemAdd(query as CFDictionary, nil)
}
saveSecretToKeychain()
Para requisitos de seguridad más complejos, como exigir la presencia del usuario o implementar contraseñas específicas de la aplicación, utilice SecAccessControlCreateWithFlags para crear un control de acceso con indicadores adicionales.
| Caso de Uso | Protección | Indicadores |
|---|---|---|
| Manejo de datos sensibles que requieren la presencia del usuario | kSecAttrAccessibleWhenUnlocked |
kSecAccessControlUserPresence |
| Manejo de datos sensibles que requieren una contraseña específica para mayor seguridad | kSecAttrAccessibleWhenPasscodeSet |
kSecAccessControlApplicationPassword |
Ejemplo:
import Foundation
import Security
func saveSecretToKeychain() {
let secretData = "mySecretPassword".data(using: .utf8)!
let access = SecAccessControlCreateWithFlags(
nil,
kSecAttrAccessibleWhenUnlocked,
kSecAccessControlUserPresence,
nil
)
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: "myAccount",
kSecValueData as String: secretData,
kSecAttrAccessControl as String: access!,
]
SecItemAdd(query as CFDictionary, nil)
}
saveSecretToKeychain()
Enlaces
- Documentación de Apple: Restricción de la accesibilidad a elementos de keychain
- Autenticación Biométrica Móvil Segura
Estándares
- OWASP_MASVS_L2:
- MSTG_AUTH_8
- GDPR:
- ART_5
- ART_25
- ART_32
- PCI_STANDARDS:
- REQ_6_2
- REQ_6_3
- REQ_8_3
- REQ_11_3
- SOC2_CONTROLS:
- CC_2_1
- CC_4_1
- CC_6_1
- CC_7_1
- CC_7_2
- CC_7_4
- CC_7_5
- CNIL_FOR_EDITORS:
- EDITORS_1_3_1
- HIPAA_CONTROLS:
- SECURITY251
- SECURITY212
- SECURITY213