求助:如何在Swift Network Framework中实现证书固定(Cert Pinning)
在Network Framework中实现证书固定的完整方案
你可以通过SecTrust对象提取服务器证书,完成自定义证书固定逻辑,以下是可直接复用的实现方案:
核心实现逻辑
- 预先将目标服务器的证书哈希(推荐SHA256)或证书数据存入本地(可硬编码或从资源文件读取)
- 在
sec_protocol_options_set_verify_block回调中,从SecTrust提取服务器证书链 - 对比服务器证书与本地存储的固定值,验证通过则完成信任校验
完整代码示例
// 预先存储的服务器证书SHA256哈希(替换为你的证书实际哈希值) let pinnedCertSHA256 = "ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890" sec_protocol_options_set_verify_block(options.securityProtocolOptions, { (metadata, secTrust, complete) in let trust = sec_trust_copy_ref(secTrust).takeRetainedValue() // 1. 从SecTrust中获取服务器证书链的叶子证书(第一个证书) guard let serverCert = SecTrustGetCertificateAtIndex(trust, 0) else { complete(false) return } // 2. 提取证书的SHA256哈希 guard let certData = SecCertificateCopyData(serverCert) as Data? else { complete(false) return } let sha256Digest = SHA256.hash(data: certData) let serverCertHash = sha256Digest.compactMap { String(format: "%02x", $0) }.joined() // 3. 对比固定的哈希值 let isPinnedCertValid = serverCertHash.lowercased() == pinnedCertSHA256.lowercased() if isPinnedCertValid { // 证书固定验证通过,同时执行系统信任校验(可选,根据业务需求调整) var error: CFError? if SecTrustEvaluateWithError(trust, &error) { complete(true) } else { complete(false) } } else { // 证书不匹配,拒绝建立连接 complete(false) } }, DispatchQueue.global())
关键细节说明
- 获取证书哈希:将服务器证书导出为DER格式后,可通过终端命令计算SHA256:
openssl dgst -sha256 -binary your-cert.cer | xxd -p -c 256 - 证书链选择:若需固定中间证书或根证书,调整
SecTrustGetCertificateAtIndex的索引值即可(索引0为叶子证书,索引越大越靠近根证书) - 系统校验取舍:如果业务仅要求证书固定,可跳过
SecTrustEvaluateWithError直接根据哈希对比结果调用complete,但保留系统校验能避免额外安全风险 - 测试环境逻辑:
allowInsecure分支仅用于测试,生产环境必须移除,禁止绕过证书校验
内容的提问来源于stack exchange,提问作者Natto
相关产品推荐
相关产品推荐

