HTTP Public Key Pinning 介绍
上篇文章中,我介绍了由 Google 推动的 Certificate Transparency 技术,它旨在通过开放的审计和监控系统,提高 HTTPS 网站证书安全性。本文要介绍的 HTTP Public Key Pinning(HPKP),也是用来防范由「伪造或不正当手段获得网站证书」造成的中间人攻击,但有着与 CT 不同的思路。
我们知道,受信任的 CA(证书颁发机构)有好几百个,他们成为整个网站身份认证过程中一个较大的攻击面。现有的证书信任链机制最大的问题是,任何一家受信任的 CA 都可以签发任意网站的站点证书,这些证书在浏览器看来,都是合法的。前面提到的 CT 技术能改善这种情况,但 CT 还没有普及,现阶段浏览器不能贸然阻断没有提供 SCT 信息的 HTTPS 网站。
HPKP 技术给予我们主动选择信任 CA 的权利。它的工作原理是通过响应头或者 <meta>
标签告诉浏览器当前网站的证书指纹,以及过期时间等其它信息。未来一段时间内,浏览器再次访问这个网站必须验证证书链中的证书指纹,如果跟之前指定的值不匹配,即便证书本身是合法的,也必须断开连接。
HPKP 官方文档见 RFC7469,目前 Firefox 35+ 和 Chrome 38+ 已经支持。它的基本格式如下:
Public-Key-Pins: pin-sha256="base64=="; max-age=expireTime [; includeSubdomains][; report-uri="reportURI"]
各字段含义如下:
pin-sha256
即证书指纹,允许出现多次(实际上最少应该指定两个);max-age
和includeSubdomains
分别是过期时间和是否包含子域,它们在 HSTS(HTTP Strict Transport Security)中也有,格式和含义一致;report-uri
用来指定验证失败时的上报地址,格式和含义跟 CSP(Content Security Policy)中的同名字段一致;includeSubdomains
和report-uri
两个参数均为可选;
pin-sha256
应该如何指定?显然,为了验证合法性,服务端给出的 pin-sha256
必须由网站当前证书链中的证书生成。例如我的网站证书有三级,用根证书、中间证书、站点证书中的任何一个生成指纹都可以。用站点证书生成指纹的好处是安全性最高,缺点是证书重签之后指纹就变了,如果之前没提供备用指纹,老用户无法访问;用根证书生成指纹安全性最差,因为每个根证书都对应很多中间证书,攻击者只要攻破其中一个,就可以签出能被 HPKP 策略信任的站点证书。
综合考虑安全性和易用性,一般推荐使用中间证书生成指纹;用知名 CA 的根证书也可以;不推荐使用站点证书,除非充分了解后果并且指定了有效的备用指纹。
备用指纹是为那些必须更换中间或者根证书的场景准备的 —— 例如原来的 CA 突然倒闭或者被黑了。本站当前使用的证书由 RapidSSL SHA256 CA - G4 签发,我的 pin-sha256
包含了它的指纹;同时我还用 Let's Encrypt Authority X1 这个中间证书生成了备用指纹。这样如果后续本站改为使用 Let's Encrypt Authority X1 签发的证书,老用户也不会受影响。
使用 openssl 生成证书 Public Key 指纹很简单,下面简单介绍下。
建议先验证证书是否有误:
openssl x509 -in intermediate.pem -noout -subjectsubject= /C=US/O=GeoTrust Inc./CN=RapidSSL SHA256 CA - G4
通过 CN(Common Name)字段可以确认这就是本站的中间证书。接着,生成 Public Key:
openssl x509 -in intermediate.pem -noout -pubkey | openssl asn1parse -noout -inform pem -out public.key
生成指纹:
openssl dgst -sha256 -binary public.key | openssl enc -base64aef6IF2UF6jNEwA2pNmP7kpgT6NFSdt7Tqf5HzaIGWI=
按照同样方法,生成其它中间证书的备用指纹。最后修改 Nginx 配置并重新加载即可。以下是本站的 HPKP 配置:
add_header Public-Key-Pins 'pin-sha256="aef6IF2UF6jNEwA2pNmP7kpgT6NFSdt7Tqf5HzaIGWI="; pin-sha256="YLh1dUR9y6Kja30RrAn7JKnbQG/uEtLMkBgFF2Fuihg="; max-age=2592000; includeSubDomains';
一切妥当后,可以通过 SSL Labs 这个服务来验证 HPKP 是否正常:
也可以在 Chrome 中访问 chrome://net-internals/#hsts
页面,查看指定域名的 HPKP 信息:
也许有人要问,如果用户第一次访问就被劫持怎么办?
跟 HSTS 一样,HPKP 依赖于服务端响应头,对于用户首次访问就被劫持这种情况无能为力。这个问题也只能通过浏览器内置 Preload List 来解决,现阶段 Chrome 已经内置了自家域名和各大知名网站的 HPKP 信息。不同于 HSTS Preload List,目前我没有找到个人网站申请加入 HPKP Preload List 的入口,如果你知道怎么做,不妨留言告诉我。
扫一扫订阅我的微信号:IT技术博客大学习
- 作者:JerryQu 的小站 来源: JerryQu 的小站
- 标签: HPKP pinning
- 发布时间:2016-04-02 22:36:28
- [54] IOS安全–浅谈关于IOS加固的几种方法
- [52] android 开发入门
- [52] 如何拿下简短的域名
- [51] 图书馆的世界纪录
- [49] Go Reflect 性能
- [49] Oracle MTS模式下 进程地址与会话信
- [47] 【社会化设计】自我(self)部分――欢迎区
- [46] 读书笔记-壹百度:百度十年千倍的29条法则
- [37] 程序员技术练级攻略
- [29] 视觉调整-设计师 vs. 逻辑