证书固定(pinning)在 CA 校验之上再限定服务器只能用哪个公钥。pin 怎么算、轮换时怎么不出事故、不验证只 pin 有什么风险?这篇用本机自建的 CA 与 TLS 服务逐项真实验证,并用 openssl 与 curl 交叉核对 pin 值。
openssl x509 -pubkey | openssl pkey -pubin -outform der | sha256 → base64:zSW3rbSEHe8FBvmi+f3kZnZesyS6CSfanYpxyQSFI/E=(叶子 A 的 pin) curl --pinnedpubkey sha256//…(正确的 pin(A 的公钥))→ curl 返回码 0,HTTP 200 curl --pinnedpubkey sha256//…(另一个证书 B 的 pin)→ curl 返回码 90,HTTP 000; curl --pinnedpubkey sha256//…(根证书的 pin)→ curl 返回码 90,HTTP 000;
Java 里按 SubjectPublicKeyInfo 算出的 pin(A.crt 的叶子)= zSW3rbSEHe8FBvmi+f3kZnZesyS6CSfanYpxyQSFI/E=,与 openssl 算出的一致 = true
只做普通 PKIX 校验(信任 root,不 pin),服务器证书 A → 连接成功
pin = A 的公钥(叶子),服务器证书 A → 连接成功
pin = A 的公钥,服务器换成证书 B(新密钥,同一个 CA 签发,PKIX 本身可以通过)→ 失败:CertificateException: 证书链里没有任何一个公钥匹配 pin(链长 2)
pin = A 的公钥,服务器换成证书 A2(同一个密钥重新签发了新证书)→ 连接成功
pin = {A, B}(当前 + 备用),服务器换成 B → 连接成功
pin = 根 CA 的公钥,服务器 B(链里含根)→ 连接成功;服务器 A → 连接成功
pin 集合为空 → 失败:CertificateException: 证书链里没有任何一个公钥匹配 pin(链长 2)已过期的证书 X(PKIX 可以识别)且 pin 匹配:只 pin、不做 PKIX → 连接成功 同一个过期证书,PKIX + pin → 失败:CertificateExpiredException: NotAfter: Wed Aug 05 08:00:00 CST 2026 主机名不符的证书 H(CN=wrong.example,CA 签发),连接 localhost:PKIX + pin + 主机名检查(HTTPS)→ 失败:CertificateException: No subject alternative DNS name matching localhost found. 同一个 H 证书,不设 endpointIdentificationAlgorithm(不检查主机名)→ 连接成功(pin 只比较公钥,不检查证书里的名字)