Mic.Run

Back

TL;DR

太长不看?先看结论!
  • 直接解法:服务端换成权威 CA 签发的证书,客户端删除自定义 TrustManager,让 OkHttp 使用默认信任链,然后保留 CertificatePinner 做证书钉扎。
  • 不要用“全部信任”的 TrustManager 绕过自签名证书错误:自定义 TrustManager 后 OkHttp 拿不到预期的证书链指纹,CertificatePinner 仍会报 SSLPeerUnverifiedException。

最近在写一些用 HTTPS 通讯的程序,最初因为使用了 Cloudflare 而受到免费计划的 SSL 限制。 更换到国内 CDN 后想用自签名证书给 API 接口用,发现不行,客户端会报错。

查询后发现是 OkHttp 的特别限制:

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
  Peer certificate chain: # 自定义TrustManagers后,不回报任何指纹
  Pinned certificates for api.mic.run:
    sha256/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=
	at okhttp3.CertificatePinner.check$okhttp(CertificatePinner.kt:200)
	at okhttp3.internal.connection.RealConnection.connectTls(RealConnection.kt:410)
	at okhttp3.internal.connection.RealConnection.establishProtocol(RealConnection.kt:337)
	at okhttp3.internal.connection.RealConnection.connect(RealConnection.kt:209)
	at okhttp3.internal.connection.ExchangeFinder.findConnection(ExchangeFinder.kt:226)
	at okhttp3.internal.connection.ExchangeFinder.findHealthyConnection(ExchangeFinder.kt:106)
	at okhttp3.internal.connection.ExchangeFinder.find(ExchangeFinder.kt:74)
	at okhttp3.internal.connection.RealCall.initExchange$okhttp(RealCall.kt:255)
txt

不自定义 TrustManager 的话,JDK 又会报 SSLHandshakeException,因为自签名证书不被信任。

目前我想到的解决办法就是把自己验证的逻辑丢到里面,但把 @Overwrite 那里覆盖掉就解决了验证…

在OkHTTP中自签名证书无法使用证书钉扎
https://mic.run/blog/self-signed-certificates-do-not-work-with-certificate-pinning-in-okhttp
Author Mic
Published at 2025年5月5日
Comment seems to stuck. Try to refresh?✨