Aller au contenu

Insecure Keychain Storage

Accessibilité Non Sécurisée du Keychain

Description

Le Keychain est une base de données spécialisée pour le stockage sécurisé de données sensibles sur les appareils iOS. Des données telles que des mots de passe, des clés de chiffrement ou des certificats peuvent être enregistrées dans le Keychain. Lors de la création ou de la mise à jour d'un élément du Keychain, le développeur peut déterminer les conditions dans lesquelles il peut être consulté à l'aide de l'attribut kSecAttrAccessible. L'utilisation de valeurs d'accessibilité faibles comme kSecAttrAccessibleAlways ou kSecAttrAccessibleAlwaysThisDeviceOnly permet d'accéder à l'élément du Keychain même lorsque l'appareil est verrouillé.

kSecAttrAccessibleAlways et kSecAttrAccessibleAlwaysThisDeviceOnly sont obsolètes depuis iOS 12.0 en raison des risques de sécurité. Leur utilisation peut entraîner l'exposition de données sensibles à des personnes non autorisées si l'appareil est perdu, volé ou compromis.

Dans les exemples suivants, une spécification incomplète des indicateurs de contrôle d'accès (SecAccessControlCreateFlags) entraîne un stockage non sécurisé des éléments du 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()

Dans ces exemples, il est essentiel de spécifier correctement les indicateurs de contrôle d'accès pour garantir un stockage sécurisé des éléments du keychain. Sans indicateurs spécifiques comme kSecAccessControlUserPresence, les éléments du keychain restent vulnérables à un accès non autorisé.

Recommandation

Lorsque de simples exigences de contrôle d'accès suffisent, vous pouvez spécifier directement le niveau d'accessibilité à l'aide de kSecAttrAccessible. L'omission de kSecAttrAccessControl est acceptable dans ces cas.

Cas d'utilisation Protection
Stockage de données toujours accessibles kSecAttrAccessibleAlways
Stockage de données accessibles après le premier déverrouillage kSecAttrAccessibleAfterFirstUnlock
Stockage de données accessibles uniquement lorsque l'appareil est déverrouillé kSecAttrAccessibleWhenUnlocked

Exemple:

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()

Pour des exigences de sécurité plus complexes, telles que l'exigence de la présence de l'utilisateur ou la mise en œuvre de mots de passe spécifiques à l'application, utilisez SecAccessControlCreateWithFlags pour créer un contrôle d'accès avec des indicateurs supplémentaires.

Cas d'utilisation Protection Indicateurs
Traitement de données sensibles nécessitant la présence de l'utilisateur kSecAttrAccessibleWhenUnlocked kSecAccessControlUserPresence
Traitement de données sensibles nécessitant un mot de passe spécifique pour une sécurité accrue kSecAttrAccessibleWhenPasscodeSet kSecAccessControlApplicationPassword

Exemple:

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()

Liens

Normes

  • 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