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