在 OkHttp 中如何实现证书锁定?需要注意哪些潜在风险?
解读
面试官问“证书锁定”并不是想听“把证书拷进去就行”这种一句话答案,而是考察:
- 你是否真的在生产环境做过 HTTPS 加固;
- 是否理解国内“根证书不可控、中间人频发”的痛点;
- 能否权衡安全与运维成本,给出可落地的方案。
因此,回答必须包含:代码实现、公钥/证书两种锁定方式、灰度与热更新机制、国内厂商 ROM 与代理环境的兼容性、以及踩坑案例。
知识点
- CertificatePinner 是 OkHttp 提供的官方 API,支持 SHA-256 公钥哈希锁定,可绑定域名。
- 锁定粒度:可锁“整链”(certificate) 也可锁“公钥”(public key);国内推荐锁公钥,避免证书续期即失效。
- 哈希算法:OkHttp 只认 SHA-256,不能用 SHA-1。
- 异常类型:CertificatePinner 校验失败会抛 SSLPeerUnverifiedException,需自定义 UncaughtExceptionHandler 防止直接 Crash。
- 国内特殊场景:
- 公司网关代理(如蓝盾、奇安信)会动态下发私有 CA,需内置“调试白名单”开关;
- 部分政企 ROM 把用户证书置为系统级,导致锁定失效,需双重校验;
- 小程序/混合栈内嵌 WebView 不走 OkHttp,需同步做 onReceivedSslError 拦截。
- 运维风险:证书续期、CDN 多域名、双证书(RSA/ECC)轮换,必须提前 90 天做灰度,否则一次回滚就是全网断网。
- 合规:工信部 164 号文要求 App 不得影响用户接入合法代理,锁定逻辑需保留“用户手动信任入口”并弹窗告知,否则上架审核会被驳回。
答案
“我在上一个金融 App 里用 OkHttp 做证书锁定,分四步落地:
- 提取公钥哈希:把服务器返回的证书链打印出来,用 openssl x509 -pubkey | openssl rsa -pubin -outform DER | sha256sum 得到 32 字节哈希,填到 strings.xml,方便云端动态下发。
- 构建 CertificatePinner: val pinner = CertificatePinner.Builder() .add("*.mybank.com", "sha256/afwiX3aDzZ...") .add("open.mybank.com", "sha256/BLAHBLAH...") .build() 注意通配符只能匹配一级子域,国内 CDN 经常换域名,我把所有可能域名都显式列出来,避免遗漏。
- 注入 OkHttpClient: val client = OkHttpClient.Builder() .certificatePinner(pinner) .build() retrofit 实例统一用这一份 client,防止有人私自 newClient 绕过锁定。
- 灰度与热更新:把哈希列表做成 AES 加密的后台接口,每 6 小时同步一次;同时内置空哈希做兜底,一旦后台返回空数组就自动降级为只校验系统根证书,防止我方的 SRE 操作失误把正确哈希冲掉。
潜在风险我踩过三个坑:
- 证书续期忘了提前灰度,结果新证书公钥变了,用户大面积无法登录,最后紧急发热修包,把新哈希硬编码进去。
- 政企 Wi-Fi 环境用了私有 CA,导致 SSLPeerUnverifiedException,我们加了白名单弹窗,让用户手动选择是否信任,否则无法过工信部检测。
- 测试同学用 Charles 抓包,开了全局代理,结果锁定直接失败,我们在 debug 包用 BuildConfig 开关跳过锁定,release 包强制开启,并把日志脱敏,防止把哈希打印到 logcat。”
拓展思考
- 双证书策略:RSA 与 ECC 共存时,可一次性把两个公钥哈希都写进 CertificatePinner,实现无缝轮换。
- 公钥哈希备份:在 TEE 或 Android Keystore 里存一份哈希签名,防止恶意进程在内存中 patch Builder。
- 自动化测试:用 MockWebServer + custom trust manager 构造“错误证书”场景,把锁定失败路径纳入 CI,否则回归测试永远只走 happy path。
- 与 SSL pinning bypass 框架的攻防:国内黑产用 Xposed 模块“JustTrustMe”可一键绕过,如果 App 有合规审计需求,需在 native 层再用 libssl 做二次校验,形成 Java+Native 双保险。
- 未来趋势:Google 在推 Android 14 的“透明证书锁定”(Transparency Log Pinning),要求把锁定哈希上传到 CT Log,国内生态尚未落地,但银行类 App 建议提前研究,避免政策突然收紧。