跳到主要内容

Keychain 与数据加密

问题

iOS 中如何安全存储敏感数据?

答案

Keychain

Keychain 是 iOS 提供的系统级加密存储,存储在硬件安全芯片(Secure Enclave)保护下:

import Security

// 存储
func saveToKeychain(key: String, value: String) -> Bool {
guard let data = value.data(using: .utf8) else { return false }
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data,
kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlockedThisDeviceOnly
]
SecItemDelete(query as CFDictionary)
return SecItemAdd(query as CFDictionary, nil) == errSecSuccess
}

// 读取
func readFromKeychain(key: String) -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecReturnData as String: true
]
var result: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &result)
guard status == errSecSuccess, let data = result as? Data else { return nil }
return String(data: data, encoding: .utf8)
}

CryptoKit 加密

import CryptoKit

// AES-GCM 对称加密
let key = SymmetricKey(size: .bits256)
let plaintext = "敏感数据".data(using: .utf8)!
let sealedBox = try AES.GCM.seal(plaintext, using: key)
let ciphertext = sealedBox.combined!

// 解密
let openedBox = try AES.GCM.SealedBox(combined: ciphertext)
let decrypted = try AES.GCM.open(openedBox, using: key)

// SHA256 哈希
let hash = SHA256.hash(data: plaintext)

存储安全等级

方式安全级别适合存储
UserDefaults❌ 明文 plist用户偏好
文件系统⚠️ 需手动加密普通文件
Keychain✅ 系统加密Token、密码、密钥
Secure Enclave✅✅ 硬件级生物识别密钥

常见面试问题

Q1: Keychain 和 UserDefaults 存 Token 的区别?

答案:UserDefaults 以明文 plist 存储,越狱设备可直接读取。Keychain 由系统加密保护,App 卸载后数据仍保留(除非指定 ThisDeviceOnly),安全性远高于 UserDefaults。

相关链接