HTTP公钥固定(Public Key Pinning)扩展:HPKP 详解

2019-11-29 17:48:19  阅读 19 次 评论 0 条

一、什么是HPKP?

HTTP公钥固定(HPKP)是一种安全功能,它告诉Web客户端将特定加密公钥与某个Web服务器相关联,以降低使用伪造证书进行“MITM攻击(中间人攻击)”的风险。

 

为了确保TLS会话中使用的服务器公钥的真实性,此公钥将包装到X.509证书中,该证书通常由证书颁发机构(CA)签名。诸如浏览器之类的Web客户端信任许多这些CA,它们都可以为任意域名创建证书。如果攻击者能够破坏单个CA,则他们可以对各种TLS连接执行MITM攻击。 HPKP可以通过告知客户端哪个公钥属于某个Web服务器来规避HTTPS协议的威胁。

 

HPKP是首次使用信任(TOFU)技术。 Web服务器第一次通过特殊的HTTP头告诉客户端哪些公钥属于它,客户端将该信息存储在给定的时间段内。当客户端再次访问服务器时,它希望证书链中至少有一个证书包含一个公钥,其指纹已通过HPKP获知。如果服务器提供未知的公钥,则客户端应向用户发出警告。

 

二、如何查看网站是否成功启动HPKP?

直接可以用浏览器F12调试来查看;下图我是用的火狐浏览器查看的,结果是“公钥固定:已禁用”。

公钥固定HPKP 已禁用

 

二、如何启用HPKP?

要为您的站点启用此功能,您需要在通过HTTPS访问站点时返回Public-Key-Pins HTTP标头:

Public-Key-Pins: pin-sha256="base64=="; max-age=expireTime [; includeSubDomains][; report-uri="reportURI"]

pin-sha256

引用的字符串是Base64编码的主体公钥信息(SPKI)指纹, 可以为不同的公钥指定多个引脚。 某些浏览器将来可能允许使用其他哈希算法而不是SHA-256。 请参阅下文,了解如何从证书或密钥文件中提取此信息。

这里可以使用OpenSSL 命令来生成 SPKI 指纹。

 

max-age

浏览器应记住仅使用其中一个已定义的密钥访问此站点的时间(以秒为单位)。

 

includeSubDomains 可选

如果指定了此可选参数,则此规则也适用于所有站点的子域。

 

report-uri 可选

如果指定了此可选参数,则会将引脚验证失败报告给给定的URL。

 

首先,您需要从证书或密钥文件中提取公钥信息,并使用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

 

最终结果示例:HPKP头

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”解释了报告引脚验证失败的位置。

 

Report-Only header

您也可以使用Public-Key-Pins-Report-Only标头,而不是使用Public-Key-Pins标头。 此标头仅将报告发送到标头中指定的report-uri,并且即使违反了固定,仍允许浏览器连接到Web服务器。

 

设置您的Web服务器以包含HPKP header

传递HPKP标头所需的具体步骤取决于您使用的Web服务器。下面再说说Apache、Nginx、Lighttpd、IIS分别如何设置HPKP?

 

Apache

在Web服务器的配置中添加类似于以下内容的行将在您的Apache上启用HPKP。 这需要启用mod_headers。

Header always set Public-Key-Pins "pin-sha256=\"base64+primary==\"; pin-sha256=\"base64+backup==\"; max-age=5184000; includeSubDomains"

 

Nginx

添加以下行并插入适当的 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;

 

Lighttpd

以下包含相关密钥信息的行(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" )

 

IIS

将以下行添加到Web.config文件以发送Public-Key-Pins标头:

<system.webServer>
  ...  <httpProtocol>
    <customHeaders>
      <add name="Public-Key-Pins" value="pin-sha256=&quot;base64+primary==&quot;; pin-sha256=&quot;base64+backup==&quot;; max-age=5184000; includeSubDomains" />
    </customHeaders>
  </httpProtocol>

  ...</system.webServer>


本文地址:http://daiguohui.com/post/14.html
版权声明:本文为原创文章,版权归 daiguohui 所有,欢迎分享本文,转载请保留出处!

发表评论


表情

还没有留言,还不快点抢沙发?