跳到主要内容

网络安全

问题

iOS 网络安全有哪些措施?如何实现 SSL Pinning?

答案

iOS 网络安全层次

层次措施
传输层HTTPS / TLS 加密
系统级App Transport Security(ATS)
应用级SSL Pinning(证书固定)
数据级敏感数据加密存储

SSL Pinning 实现

固定服务器证书的公钥,防止中间人攻击:

class NetworkDelegate: NSObject, URLSessionDelegate {
// 服务器公钥的 SHA256 指纹
private let pinnedKeyHash = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="

func urlSession(_ session: URLSession,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
let serverTrust = challenge.protectionSpace.serverTrust else {
completionHandler(.cancelAuthenticationChallenge, nil)
return
}

// 获取服务器证书的公钥
if let serverKey = SecTrustCopyKey(serverTrust) {
let serverKeyData = SecKeyCopyExternalRepresentation(serverKey, nil)! as Data
let keyHash = serverKeyData.sha256().base64EncodedString()

if keyHash == pinnedKeyHash {
completionHandler(.useCredential, URLCredential(trust: serverTrust))
return
}
}

completionHandler(.cancelAuthenticationChallenge, nil)
}
}

Alamofire SSL Pinning

let evaluators: [String: ServerTrustEvaluating] = [
"api.example.com": PublicKeysTrustEvaluator() // 公钥固定
// 或 PinnedCertificatesTrustEvaluator() // 证书固定
]

let manager = ServerTrustManager(evaluators: evaluators)
let session = Session(serverTrustManager: manager)
证书固定的维护

证书有有效期,更换证书后旧版 App 会无法连接。推荐固定公钥(而非证书本身),因为续期证书时公钥通常不变。同时在 App 中预置多个备用公钥。


常见面试问题

Q1: HTTPS 能完全防止中间人攻击吗?

答案:不能。如果用户安装了恶意 CA 证书(如公司代理),中间人可以签发被系统信任的伪造证书。SSL Pinning 可以防御这种攻击——即使中间人的证书被系统信任,公钥指纹不匹配也会拒绝连接。

Q2: 如何在 Charles/Proxyman 中调试 HTTPS?

答案

  1. 在设备上安装并信任 Charles 的 CA 证书
  2. 如果 App 使用了 SSL Pinning,需要在 Debug 环境禁用 Pinning
  3. 可以通过编译宏 #if DEBUG 控制是否启用 Pinning

相关链接