コンテンツにスキップ

Insecure Keychain Storage

安全でないKeychainのアクセシビリティ

説明

Keychainは、iOSデバイス上で機密データを安全に保存するための特化したデータベースです。パスワード、暗号化キー、または証明書などのデータをKeychainに保存できます。 Keychainアイテムを作成または更新する際、開発者はkSecAttrAccessible属性を使用してアクセス可能な条件を決定できます。kSecAttrAccessibleAlwayskSecAttrAccessibleAlwaysThisDeviceOnlyのような脆弱なアクセシビリティ値を使用すると、デバイスがロックされている状態でもKeychainアイテムにアクセスできるようになります。

セキュリティ上のリスクから、kSecAttrAccessibleAlwaysおよびkSecAttrAccessibleAlwaysThisDeviceOnlyはiOS 12.0以降で非推奨となりました。これらを使用すると、デバイスの紛失、盗難、または侵害が発生した場合に、機密データが権限のない第三者に漏洩する可能性があります。

以下の例では、アクセス制御フラグ(SecAccessControlCreateFlags)の指定が不完全であるため、安全でない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()

これらの例では、Keychainアイテムを安全に保存するために、アクセス制御フラグを適切に指定することが重要です。kSecAccessControlUserPresenceのような特定のフラグがない場合、Keychainアイテムは不正アクセスの脆弱性にさらされたままになります。

推奨事項

単純なアクセス制御の要件で十分な場合は、kSecAttrAccessibleを使用してアクセシビリティレベルを直接指定できます。このような場合、kSecAttrAccessControlを省略することは許容されます。

ユースケース 保護
常にアクセス可能なデータの保存 kSecAttrAccessibleAlways
初回ロック解除後にアクセス可能なデータの保存 kSecAttrAccessibleAfterFirstUnlock
デバイスのロック解除時のみアクセス可能なデータの保存 kSecAttrAccessibleWhenUnlocked

:

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

ユーザーの存在を要求したり、アプリケーション固有のパスワードを実装したりするなど、より複雑なセキュリティ要件がある場合は、SecAccessControlCreateWithFlagsを使用して追加のフラグとともにアクセス制御を作成します。

ユースケース 保護 フラグ
ユーザーの存在を必要とする機密データの処理 kSecAttrAccessibleWhenUnlocked kSecAccessControlUserPresence
さらなるセキュリティのために特定のパスワードを必要とする機密データの処理 kSecAttrAccessibleWhenPasscodeSet kSecAccessControlApplicationPassword

:

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

リンク

標準

  • 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