我的一次 HPKP 坑自己经历

背景

HTTP Public Key Pinning (HPKP) 是一项通过 HTTP 头定义网站所使用的 SSL 证书的 Hash 值,在一段时间内防止被第三方进行中间人攻击的方案。通过声明 HPKP ,浏览器会在有效期内保存网站所提供的 HPKP ,并且检验当前的 SSL 证书是否在 HPKP 允许的范围内,如果不在,则会直接不允许访问,并且还没有手动忽略的选择。

几个月前,我在 SSLLABS 上看到了有这个选项,于是兴致勃勃的给自己的网站加上了 HPKP 头,当时没想这么多,就 PIN 了当时正在使用的 Comodo 证书以及打算使用的 Let‘s encrypt 的证书。

前几天,我打算将网站通过 CloudFlare 加一层 CDN ,于是故事开始了。

故障

刚开始问题切换过去 CloudFlare,我还没觉得有什么问题。由于 CloudFlare 的证书签发需要时间,我将域名解析过去之后便睡觉了,第二天就有人来和我说我的网站打不开了,提示证书出了问题。

打开浏览器,Chrome 立马就报错了(截图大概就是下面这样子..我自己忘记截图了)

NET::ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN

分析

我原先使用的 HPKP 头是

Public-Key-Pins 'pin-sha256="EohwrK1N7rr3bRQphPj4j2cel+B2d0NNbM9PWHNDXpM="; pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; max-age=2592000; includeSubDomains'

其中分别包含了两张证书

COMODO ECC Domain Validation Secure Server CA
EohwrK1N7rr3bRQphPj4j2cel+B2d0NNbM9PWHNDXpM=
Let's Encrypt Authority X3
YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg=

并且要求浏览器缓存 2592000 秒也就是 30 天,并且对全部子域名生效。

而切换到 CloudFlare 之后,SSL 证书的中级证书变成了:

COMODO ECC Domain Validation Secure Server CA 2

Pin SHA256 的值也不同了,变成了:

x9SZw6TwIqfmvrLZ/kz1o0Ossjmn728BnBKpUFqGNVM=

由于 CA 2 的 Pin SHA256 值之前并没有包括在内,因此浏览器阻止了我们的访问。

解决方案

  1. 切换回原来的服务器,继续使用 Let's Encrypt 签发的 SSL 证书
  2. 修改 HPKP 头,增加 EULHwYvGhknyznoBvyvgbidiBH3JX3eFHHlIO3YK8Ek=
  3. 等待一个月后,再次切换到 CloudFlare