21. 安全与加密
安全能力主要体现在三点:通信安全、数据安全、密钥管理。
一、ATS 与 HTTPS
iOS 默认要求 HTTPS,除非在 Info.plist 中显式配置例外。线上不要关闭 ATS。
二、证书校验(Pinning)
import Foundation
final class PinnedSessionDelegate: NSObject, URLSessionDelegate {
private let pinnedData: Data
init(pinnedCertData: Data) {
self.pinnedData = pinnedCertData
}
func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
guard let serverTrust = challenge.protectionSpace.serverTrust,
let cert = SecTrustGetCertificateAtIndex(serverTrust, 0) else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}
let serverData = SecCertificateCopyData(cert) as Data
if serverData == pinnedData {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
} else {
completionHandler(.cancelAuthenticationChallenge, nil)
}
}
}
三、CryptoKit 哈希
import CryptoKit
func sha256(_ input: String) -> String {
let data = Data(input.utf8)
let hash = SHA256.hash(data: data)
return hash.compactMap { String(format: "%02x", $0) }.joined()
}
四、HMAC 签名
import CryptoKit
func hmacSHA256(message: String, key: String) -> String {
let keyData = SymmetricKey(data: Data(key.utf8))
let signature = HMAC<SHA256>.authenticationCode(for: Data(message.utf8), using: keyData)
return signature.map { String(format: "%02x", $0) }.joined()
}
五、敏感数据存储
敏感数据不要放 UserDefaults,必须用 Keychain。
import Security
func saveToken(_ token: Data) {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrService as String: "token",
kSecValueData as String: token
]
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
安全不是一次性的功能,是长期能力:传输、存储、权限全部要一致。