Alamofire公钥固定失效问题排查及相关疑问求助
Alamofire + Moya 公钥固定问题排查与解决方案
一、证书读取失败:Bundle.main.af.publicKeys为空
核心原因
Alamofire 的 Bundle.af.publicKeys 仅支持 DER 格式 的 .cer/.crt 证书,PEM 格式证书会因为 SecCertificateCreateWithData 解析失败,无法生成公钥对象,导致返回空数组。
解决步骤
- 正确转换证书格式
使用 OpenSSL 将 PEM 证书转为 DER 格式,命令如下:openssl x509 -in 原证书.pem -outform der -out 目标证书.cer - 确保证书正确导入项目
- 将转换后的
.cer文件拖入 Xcode 项目,勾选「Copy items if needed」 - 检查 Target 的
Build Phases > Copy Bundle Resources中是否包含该证书,确保打包时能被放入 Bundle
- 将转换后的
二、证书正常但请求返回 405,!pinnedKeysInServerKeys 为 false
关键概念区分
- 405 Method Not Allowed:这是 HTTP 层状态码,说明服务器已完成 TLS 握手(公钥校验大概率已通过),但请求使用的 HTTP 方法(如 GET/POST)不符合服务器接口要求。
pinnedKeysInServerKeys返回 false:表示本地固定的公钥与服务器返回的公钥无匹配,理论上会触发 TLS 信任评估失败(抛出证书不信任错误),但如果仍能拿到 405,说明公钥校验逻辑可能未生效。
排查与解决
先排除 HTTP 方法错误
用 Postman 或 curl 测试同一接口,确认使用的 HTTP 方法是否符合服务器要求(比如接口仅支持 POST,但你用了 GET)。检查公钥固定配置是否生效
- 确认
ServerTrustManager已正确关联到 Alamofire Session,且域名匹配:// 初始化公钥评估器 let evaluator = PublicKeysTrustEvaluator( keys: Bundle.main.af.publicKeys, performDefaultValidation: true, validateHost: true ) // 绑定目标域名 let serverTrustManager = ServerTrustManager(evaluators: [ "your-api-domain.com": evaluator ]) // 创建带信任管理的 Session let session = Session(serverTrustManager: serverTrustManager) // 传入 Moya Provider let provider = MoyaProvider<YourAPI>(session: session) - 打印
Bundle.main.af.publicKeys.count,确认公钥已成功加载(数量 > 0)。
- 确认
验证公钥校验逻辑是否触发
自定义信任评估器添加日志,确认校验过程:class LoggingPublicKeysEvaluator: PublicKeysTrustEvaluator { override func evaluate(_ trust: SecTrust, forHost host: String) throws { let serverKeys = try ServerTrustPolicy.publicKeys(for: trust) let pinnedKeysCount = self.keys.count let serverKeysCount = serverKeys.count let isMatch = pinnedKeysInServerKeys(self.keys, serverKeys) print("本地公钥数:\(pinnedKeysCount),服务器公钥数:\(serverKeysCount)") print("公钥匹配结果:\(isMatch)") try super.evaluate(trust, forHost: host) } }替换原评估器后,查看日志输出,确认是否真的触发了公钥校验,以及匹配结果是否符合预期。
内容的提问来源于stack exchange,提问作者paprika
相关产品推荐
相关产品推荐

