申明
HPKP在现有互联网没有实质性作用,例如Google已宣布弃用HPKP
配置HPKP的唯一作用是在SSL安全性检测中给你加一点分数(是的这还可以加分)
Google在Chrome移除HPKP
参与撰写和制定该标准(RFC 7469)的谷歌工程师称:公钥固定变得非常可怕,该标准会对生态造成严重危害。除了恶意攻击者可以伪造 HPKP 头进行拒绝访问攻击外,如果证书发生泄露需要进行吊销也会引发较大问题。因为吊销旧证书后再请求签发新证书只能选择此前固定的 CA 机构,你不能再选择新的 CA 机构为你签发证书。
使用HPKP并不是将一个设置开启、关闭那么简单,配置过程有许多细节要注意。你应该固定证书链的那一部分(用户证书、中级证书、根证书)?你应该固定多少个备份证书?在一个证书颁发机构不可信或不兼容的情况下,你是否需要从多个证书颁发机构固定证书?你需要小心翼翼地配置这些策略并不断维护,错误配置HPKP可能导致网站无法访问。
安全研究员斯科特称攻击者可劫持用户访问并返回恶意 HPKP 头,这种操作虽然不会造成用户的数据发生泄露,但恶意HPKP头在被浏览器接收后会阻止用户正常访问网站,因为浏览器校验到的HPKP头与真实服务器不同。因此恶意攻击者可以利用 HPKP 公钥固定策略,无差别的对所有HTTPS网站发起这种有点另类的拒绝访问攻击。虽然网站所有者始终没有丢失对网站和服务器的控制权,但由于固定哈希已经被接收因此没有办法清除缓存。
Netcraft 2016年3月的统计数据显示,全球仅4100个网站选择使用HPKP,在使用SSL证书的网站中仅占0.09%,而且其中有三分之一的网站HPKP配置错误。鉴于标准创建者的谷歌都已经放弃这项机制,已经实施HPKP的网站可以提前解除这项机制。
介绍
HPKP是HTTP Public Key Pinning的缩写,译为HTTP公钥钉。字面意思就是将指定的证书公钥钉在HTTP头部,通过HTTP头部设置,要求客户端只接收网站指定CA签发的证书,如果没有接收到指定的CA证书,它将拒绝创建连接。
这项机制是谷歌参与制定的,设计初衷是防止HTTPS网站被攻击者利用CA错误签发的证书进行中间人攻击。但是该机制在业界备受争议,一些HTTPS/TLS专家公开表示,绝大多数的网站不应该使用HPKP,这种机制弊大于利。谷歌安全团队Chris Palmer认为,HPKP是用一种笨拙的方式去实现其他机制和协议已经做得更好的几件事。
HTTP公钥固定(HPKP)是一种安全功能,它告诉Web客户端将特定加密公钥与某个Web服务器相关联,以降低使用伪造证书进行“MITM攻击(中间人攻击)”的风险。
为了确保TLS会话中使用的服务器公钥的真实性,此公钥将包装到X.509证书中,该证书通常由证书颁发机构(CA)签名。诸如浏览器之类的Web客户端信任许多这些CA,它们都可以为任意域名创建证书。如果攻击者能够破坏单个CA,则他们可以对各种TLS连接执行MITM攻击。 HPKP可以通过告知客户端哪个公钥属于某个Web服务器来规避HTTPS协议的威胁。
HPKP是首次使用信任(TOFU)技术。 Web服务器第一次通过特殊的HTTP头告诉客户端哪些公钥属于它,客户端将该信息存储在给定的时间段内。当客户端再次访问服务器时,它希望证书链中至少有一个证书包含一个公钥,其指纹已通过HPKP获知。如果服务器提供未知的公钥,则客户端应向用户发出警告。
配置
原理
要为您的站点启用此功能,您需要在通过HTTPS访问站点时返回 Public-Key-Pins
HTTP标头
例如:
Header add Public-Key-Pins 'pin-sha256="vRU+17BDT2iGsXvOi76E7TQMcTLXAqj0+jGPdW7L1vM="; pin-sha256="x4QzPSC810K5/cMjb05Qm4k3Bw5zBn4lTdO/nEW/Td4="; pin-sha256="4a6cPehI7OG6cuDZka5NDZ7FR8a60d3auda+sKfg4Ng="; pin-sha256="Y9mvm0exBk1JoQ57f9Vm28jKo5lFm/woKcVxrYxu80o="; pin-sha256="FEzVOUp4dF3gI0ZVPRJhFbSJVXR+uQmMH65xhs1glH4="; max-age=2592000'
pin-sha256
引用的字符串是Base64编码的主体公钥信息(SPKI)指纹, 可以为不同的公钥指定多个引脚
某些浏览器将来可能允许使用其他哈希算法而不是SHA-256
请参阅下文,了解如何从证书或密钥文件中提取此信息
这里可以使用OpenSSL 命令来生成 SPKI 指纹
max-age
浏览器应记住仅使用其中一个已定义的密钥访问此站点的时间(以秒为单位)
includeSubDomains 可选
如果指定了此可选参数,则此规则也适用于所有站点的子域
report-uri 可选
如果指定了此可选参数,则会将引脚验证失败报告给给定的URL
即 公钥固定报告
获取请求头内容
首先,您需要从证书或密钥文件中提取公钥信息,并使用Base64对其进行编码
以下命令将帮助您从密钥文件,证书签名请求或证书中提取Base64编码信息
校验证书
openssl x509 -in cert.pem -noout -subject
生成Public.key
openssl x509 -in cert.pem -noout -pubkey | openssl asn1parse -noout -inform pem -out public.key
提取Base64
openssl dgst -sha256 -binary public.key | openssl enc -base64
#结果
IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO/s=
你需要对证书链中每一段证书进行提取,并结合为一条 Public-Key-Pins
。重复操作即可
最终得到 Public-Key-Pins
pin-sha256="IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO/s="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; max-age=2592000; includeSubDomains
添加到Web服务器
请将以下内容添加至SSL访问所用的的conf文件中
Nginx
add_header Public-Key-Pins 'pin-sha256="IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO/s="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; max-age=2592000; includeSubDomains';
添加后重启服务
systemctl restart nginx
Apache
Header always set Public-Key-Pins 'pin-sha256="IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO/s="; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; max-age=2592000; includeSubDomains';
添加后重启服务
systemctl restart httpd
# 或
systemctl restart apache
Lighttpd
setenv.add-response-header = ( "Public-Key-Pins" => "pin-sha256=\"IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO/s=\"; pin-sha256=\"klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=\"; max-age=2592000; includeSubDomains")
注意:这需要加载 mod_setenv server.module
,如果尚未加载,则可以包含以下内容。
server.modules += ( "mod_setenv" )
IIS
将以下行添加到 Web.config
文件
<system.webServer>
...
<httpProtocol>
<customHeaders>
<add name="Public-Key-Pins" value="pin-sha256="IiSbZ4pMDEyXvtl7Lg8K3FNmJcTAhKUTrB2FQOaAO"; pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; max-age=2592000; includeSubDomains" />
</customHeaders>
</httpProtocol>
...
</system.webServer>
AHdark Blog已启用HPKP,您可以打开浏览器Console(F12)查看Public-Key-Pins标头。