配置Public-Key-Pins头后浏览器还是报证书错误怎么办?
我给网站配置了Public-Key-Pins头,参考了文档写死了当前证书和备用密钥的pin值,但访问时Chrome还是提示“证书无效”。明明证书指纹和includeSubDomains参数都对,是不是哪里漏了?
配置的代码是这样的:
Public-Key-Pins: pin-sha256="示例值"; pin-sha256="备用值"; max-age=518400; includeSubDomains
但控制台报错“HPKP pin验证失败”,服务器是Nginx,重启后缓存也清过了…
难道还要设置report-uri?或者因为测试环境用了自签名证书导致pin无效?其他安全头比如HSTS都正常…
另外你的配置确实少了report-uri,虽然不是导致问题的主因,但加上会更好。还有几个点需要注意:
第一,确保你pin的是证书链中正确的那个证书,一般是直接给域名签发的那个,而不是中间证书或者根证书。可以通过下面这个命令提取证书的pin值,确认下是不是配错了:
第二,max-age值别设太大,尤其在调试阶段,建议先改成60秒,不然缓存时间太长改错了都看不到效果。
第三,Nginx配置里记得把Public-Key-Pins这行放到server块里,类似这样:
最后提醒一句,HPKP这东西风险挺大,配错了可能导致网站完全不可访问,连回滚的机会都没有。Chrome从2018年起已经不支持HPKP了,现在更推荐用Certificate Transparency机制来增强安全性。实在要配的话,建议先在非核心业务上试试水。
自签名证书的问题:如果你用的是自签名证书,浏览器不会信任它,也就不会认可 pin 的有效性。HPKP 是基于信任链的,根证书必须被浏览器信任才行。用 Let's Encrypt 或其他可信 CA 签发的证书试试。
证书链不完整:Nginx 配置证书时如果没有正确拼接中间证书,会导致证书链不完整,浏览器校验失败。检查你的 crt 文件是否包含完整的证书链。
pin 值计算错误:确保 pin-sha256 的值是当前证书公钥的正确指纹。可以用如下命令生成:
如果是备用证书,也要对其公钥做同样操作。
是否启用了 HSTS:HPKP 是基于 HSTS 的,必须先设置 HSTS 头,否则浏览器不会执行 pin 校验:
Strict-Transport-Security: max-age=63072000; includeSubDomains; preloadreport-uri 是可选项:不设置不会影响 pin 生效,但加上它可以在出问题时上报,方便调试。
浏览器缓存问题:HPKP 一旦生效,浏览器会缓存很久,即使你改了配置也不会马上清除。建议测试阶段把
max-age设成小值(如 300)。如果以上都确认没问题,可以尝试用
curl -I https://yourdomain或浏览器开发者工具的“Security”标签看证书详情和响应头是否匹配。