HPKP (HTTP Public Key Pinning) 是一个加强 HTTPS 页面安全性的做法。在浏览 HTTPS 页面时,服务器主动把页面的证书公钥的指纹告诉浏览器,浏览器进行检查,如果发现指纹和证书不匹配,说明页面所用的证书不是服务器所提供的证书,也就是被中间人攻击了,于是拒绝显示页面。
这么做也有安全隐患。因为第一次浏览的时候,中间人就已经可以发送假的指纹信息给浏览器了。另外,一般服务器都不会用服务端证书生成指纹,因为服务端证书一般有效期较短,尤其是如果采用了 Let's Encrypt 的证书的话,每三个月必须更新证书,而每三个月去修改服务器设置就比较麻烦了,所以都会采用中间证书甚至是根证书的指纹。这样一旦中间人使用的证书也采用了这些中间证书或者根证书的话,比如中间人也用了 Let's Encrypt 的证书,那么 HPKP 就失效了。
所以 Chrome 正在考虑去除 HPKP 的支持。
尽管有着各种缺陷,HPKP 仍然可以提供一定程度的安全增强。所以还是有存在的价值。
之前在加速博客的时候,使用了域名 CNAME 的方式访问 CloudFront 资源,而且在 CloudFront 中开启了 ACM 证书。所以如果开启 HPKP 后,就必须添加 ACM 证书的指纹。因为这时候浏览器收到的证书会是 ACM 的证书,而收到的 HTTP 头部信息则是源服务器发送的,所以要把 ACM 证书的指纹加入源服务器的设置中。
根据 AWS 的文档,可以上传自己的证书到 ACM 并使用,或者添加 Amazon 根证书的指纹。也可以用 ACM 签发的服务端证书的指纹,但显然太麻烦,因为 ACM 证书的更新是由 ACM 管理的。自己上传的证书不算。而你需要自己手动更新服务器设置。所以要用有效期更长的 Amazon 的根证书的指纹。
Amazon 列出了使用的根证书,对于 CloudFront 所使用的 ACM 签发证书,需要使用CN=Starfield Services Root Certificate Authority - G2,O=Starfield Technologies, Inc.,L=Scottsdale,ST=Arizona,C=US
的证书的公钥指纹。
具体 HPKP 设置方法就不说了,网上搜搜很多。把 Amazon 的根证书的公钥指纹加上就可以了。
可以先设置访问量小的域名测试一下,而且有效期也最好短一点,如果有问题就去 chrome://net-internals/#hsts 清除 HPKP 设置,再修改服务器设置重新测试。特别要注意,如果设置了includeSubDomains
,就要在所有该域名的子域名设置中添加所有的 HPKP 指纹。
比如如果我的 cdn.xjpvictor.info 是 CNAME 到 CloudFront,那我需要在 xjpvictor.info 和所有 xjpvictor.info 的子域名的设置中加入 Amazon 根证书的指纹。否则如果我先访问 cdn.xjpvictor.info 我可以获得完整的指纹信息,而如果我先访问 xjpvictor.info,我就无法获得 Amazon 证书的指纹,之后再访问 cdn.xjpvictor.info 时,由于浏览器收到的 Amazon 签发的证书无法匹配之前收到的指纹,就会无法打开网页了,而且因为不匹配,浏览器也不会加载 cdn.xjpvictor.info 发送的 HTTP 头部信息,也就无法获得里面包含的指纹信息了。
Update: 2017-12-31
在2017年的最后一天,发现 cdn.xjpvictor.info 无法访问了,HPKP 出问题了,猜测是 CloudFront 证书更新所以失效,于是直接关闭了 HPKP,避免之后再次出现问题。