©
This document usesPHP Chinese website manualRelease
该公共密钥钢钉扩展HTTP(HPKP)是一种安全功能,它讲述了一个Web客户端与某个web服务器的特定密码公钥关联到降低风险中间人伪造证书的攻击。
为了确保在TLS会话中使用的服务器公钥的真实性,该公钥被封装到通常由证书颁发机构(CA)签署的X.509证书中。Web客户端(如浏览器)信任很多这些CA,它们都可以为任意域名创建证书。如果攻击者能够危害单个CA,他们可以对各种TLS连接执行MITM攻击。HPKP可以通过告诉客户端哪个公钥属于某个Web服务器来规避HTTPS协议的这种威胁。
HPKP是首次使用信托(TOFU)技术。Web服务器第一次通过特殊的HTTP头告诉客户端公钥属于它,客户端将这些信息存储一段给定的时间。当客户端再次访问服务器时,它期望证书链中至少有一个证书包含已通过HPKP识别指纹的公钥。如果服务器提供未知的公钥,则客户端应向用户提供警告。
Firefox和Chrome禁用了针对经过验证的证书链终止于用户定义的信任锚(而不是内置信任锚)的固定主机的引脚验证。这意味着对于导入自定义根证书的用户,所有钉住违规都会被忽略。
要为您的站点启用此功能,您需要在Public-Key-Pins
通过HTTPS访问站点时返回HTTP标头:
Public-Key-Pins: pin-sha256="base64=="; max-age=expireTime [; includeSubDomains][; report-uri="reportURI"]
pin-sha256
引用的字符串是Base64编码的主题公钥信息(SPKI)指纹。可以为不同的公钥指定多个引脚。未来某些浏览器可能会允许其他哈希算法而不是SHA-256。请参阅下面有关如何从证书或密钥文件中提取此信息。max-age
以秒为单位的浏览器应该记住,该站点只能使用其中一个定义的键来访问。includeSubDomains
可选如果指定了此可选参数,则此规则也适用于所有网站的子域。report-uri
可选如果指定了此可选参数,则将引脚验证失败报告给给定的URL。
注意:目前的规范要求包含一个备用密钥的第二个引脚,该密钥尚未用于生产。这允许更改服务器的公钥,而不会破坏已经注意到引脚的客户端的可访问性。例如,当前一个密钥受到攻击时,这很重要。
注意:虽然下面的示例显示了如何在服务器证书上设置管脚,但建议将管脚放置在颁发服务器证书的CA的中间证书上,以简化证书更新和轮换。
首先,您需要从证书或密钥文件中提取公钥信息并使用Base64对其进行编码。
以下命令将帮助您从密钥文件,证书签名请求或证书中提取Base64编码的信息。
openssl rsa -in my-rsa-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
openssl ec -in my-ecc-key-file.key -outform der -pubout | openssl dgst -sha256 -binary | openssl enc -base64
openssl req -in my-signing-request.csr -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
openssl x509 -in my-certificate.crt -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
以下命令将提取网站的Base64编码信息。
openssl s_client -servername www.example.com -connect www.example.com:443 | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Public-Key-Pins: pin-sha256="cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2+soZS7sWs="; pin-sha256="M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE="; max-age=5184000; includeSubDomains; report-uri="https://www.example.org/hpkp-report"
在本例中,pin-sha256 =“cUPcTAZWKaASuYWhhneDttWpY3oBAkE3h2 + soZS7sWs =”固定生产中使用的服务器公钥。第二个引脚声明pin-sha256 =“M8HztCzM3elUxkcjR2S5P4hhyBNf6lHkmjAHKhpGPWE =”也引脚备份密钥。max-age = 5184000告诉客户将这些信息存储两个月,根据IETF RFC这是一个合理的时间限制。此关键固定也适用于所有子域,这由includeSubDomains声明告知。最后,report-uri =“https://www.example.net/hpkp-report”解释报告引脚验证失败的位置。
Public-Key-Pins
您也可以使用Public-Key-Pins-Report-Only
标题,而不是使用标题。此标题仅将报告发送到report-uri
标题中指定的报告,并且仍允许浏览器连接到Web服务器,即使违反了固定也是如此。
提供HPKP头文件所需的具体步骤取决于您使用的Web服务器。
注意:这些示例使用两个月的最大年龄并包含所有子域。建议验证此设置适用于您的服务器。
如果使用不当,HPKP可能会长时间锁定用户!建议使用备份证书和/或固定CA证书。
在您的web服务器的配置文件中添加一行类似于以下内容的行将启用Apache上的HPKP。这需要mod_headers
启用。
Header always set Public-Key-Pins "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains"
添加以下行并插入适当的pin-sha256="..."
值将在您的nginx上启用HPKP。这需要ngx_http_headers_module.
add_header Public-Key-Pins 'pin-sha256="base64+primary=="; pin-sha256="base64+backup=="; max-age=5184000; includeSubDomains' always;
以下与相关密钥信息(pin-sha256 =“...”字段)的行将启用lighttpd上的HPKP。
setenv.add-response-header = ( "Public-Key-Pins" => "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains")
注意:这需要mod_setenv
加载server.module,如果尚未加载,可以将其包含在内。
server.modules += ( "mod_setenv" )
将以下行添加到Web.config文件以发送Public-Key-Pins
标头:
... ...
规范 |
标题 |
---|---|
RFC 7469,第2.1节:公钥索引 |
HTTP的公钥固定扩展 |
Feature |
Chrome |
Edge |
Firefox |
Internet Explorer |
Opera |
Safari |
---|---|---|---|---|---|---|
Basic Support |
(Yes) |
No1 |
35.0 |
? |
(Yes) |
? |
report-uri |
46 |
? |
No2 |
? |
33 |
? |
Feature |
Android |
Chrome for Android |
Edge mobile |
Firefox for Android |
IE mobile |
Opera Android |
iOS Safari |
---|---|---|---|---|---|---|---|
Basic Support |
(Yes) |
(Yes) |
? |
35.0 |
? |
(Yes) |
? |
report-uri |
(Yes) |
(Yes) |
? |
No |
? |
33 |
? |