Linux中國

在 Apache、NGINX 和 Lighttpd 上啟用 HTTP 公鑰固定擴展(HPKP)

HTTP 公鑰固定擴展

用你使用的銀行做個例子,它一直使用 CA 公司 A 為其簽發證書。但是在當前的證書體系下,CA 公司 B、CA 公司 C 和 NSA 的 CA 都能給你的銀行創建證書,而你的瀏覽器會毫無疑慮的接受它們,因為這些公司都是你所信任的根 CA。

如果你的銀行實現了 HPKP 並固定了它們的第一個中級證書(來自 CA 公司 A),那麼瀏覽器將不會接受來自CA 公司 B 和 CA 公司 C 的證書,即便它們也有一個有效的信任鏈。HPKP 也允許你的瀏覽器將這種違例行為報告給該銀行,以便銀行知道被偽造證書攻擊了。

HTTP 公鑰固定擴展是一個從2011年開始開發的針對 HTTP 用戶代理(即瀏覽器)的公鑰固定標準。它由 Google 發起,甚至在 Chrome 中實現的固定機制可以使用一個人工維護的網站公鑰固定列表,這個列表包含了固定的幾個網站的公鑰簽名。(LCTT 譯註:Chrome 和 FireFox 32 及以後版本都支持公鑰固定機制,並使用內置的人工維護的公鑰固定列表數據,這些數據隨著瀏覽器軟體的更新而更新,主要包括幾個大型站點。目前還只有 Chrome 38+ 支持通過 HTTP 響應頭傳遞公鑰固定信息。)

以下是 HPKP 的幾個功能簡述:

  • HPKP 是在 HTTP 層面設置的,使用 Public-Key-Pins (PKP)響應頭。
  • 該規則的保留周期通過 max-age 參數設置,單位是秒。
  • PKP 響應頭只能用於正確的安全加密通訊裡面。
  • 如果出現了多個這樣的響應頭,則只處理第一個。
  • 固定機制可以使用includeSubDomains參數擴展到子域。
  • 當接收到一個新的 PKP 響應頭時,它會覆蓋之前存儲的公鑰固定和元數據。
  • 公鑰固定是用哈希演算法生成的,其實是一個「主題公鑰信息(SKPI)」指紋。

本文首先會介紹一些 HPKP 工作的原理,接下來我們會展示給你如何得到需要的指紋並配置到 web 伺服器中。

SPKI 指紋 - 理論

以下摘自 Adam Langley 的帖子,我們哈希的是一個公鑰,而不是證書:

通常來說,對證書進行哈希是一個顯而易見的解決方案,但是其實這是錯的。不能這樣做的原因是 CA 證書可以不斷重新簽發:同一個公鑰、主題名可以對應多個證書,而這些證書有不同的延展或失效時間。瀏覽器從下至上地在證書池中構建證書鏈時,另外一個版本的證書可能就替代匹配了你原本所期望的證書。

舉個例子,StartSSL 有兩個根證書:一個是以 SHA1 簽名的,另外是一個是 SHA256。如果你希望固定住 StartSSL 作為你的 CA,那麼你該使用哪個證書呢?你也許可以使用這兩個,但是如果我不告訴你,你怎麼會知道還有一個根證書呢?

相反地,對公鑰進行哈希則不會有這個問題:

瀏覽器假定子證書是固定不動的:它總是證書鏈的起點。子證書所攜帶的簽名一定是一個有效的簽名,它來自其父證書給這個證書專門簽發的。這就是說,父證書的公鑰相對於子證書來說是固定的。所以可推論公鑰鏈是固定的。

唯一的問題是你不能固定到一個交叉認證的根證書上。舉個例子,GoDaddy 的根證書是 Valicert 簽名的,這是為了讓那些不能識別 GoDaddy 根證書的老客戶可以信任其證書。然而,你不能固定到 Valicert 上,因為新的客戶在證書鏈上發現了 GoDaddy 證書就會停止上溯(LCTT 譯註:所以就找不到固定信息了)。

此外,我們是對 SubjectPublicKeyInfo(SPKI)進行哈希而不是對公鑰位串。SPKI 包括了公鑰類型、公鑰自身及其相關參數。這很重要,因為如果對公鑰進行哈希就有可能導致發生曲解攻擊。對於一個 Diffie-Hellman 公鑰而言:如果僅對公鑰進行哈希,而不是對完整的 SPKI,那麼攻擊者可以使用同樣的公鑰而讓客戶端將其解釋為其它組。同樣地,這樣也有可能強制將一個 RSA 密鑰當成 DSA 密鑰解釋等等。

固定在哪裡

你應該固定在什麼地方?固定你自己的公鑰並不是一個最好的辦法。你的密鑰也許會改變或撤銷。你也許會使用多個證書,經常輪換證書的話密鑰就改變了。也許由於伺服器被入侵而撤銷證書。

最容易但是不是太安全的方法是固定第一個中級 CA 證書。該證書是簽名在你的網站證書之上的,所以簽發該證書的 CA 的公鑰肯定是在證書鏈上的。

採用這種方法你可以從同一個 CA 更新你的證書而不用擔心固定信息不對。如果該 CA 發行了一個不同的根證書,也許你會遇到一些問題,對此並沒有太好的解決方案。不過你可以通過如下做法來減輕這種問題的影響:

  • 從一個不同的 CA 申請一個備用的證書,並固定該備份。

RFC 裡面說你至少需要做兩個固定。一個是當前連接所使用的證書鏈上的,另外一個是備份的。

另外的固定是對備份公鑰的,它可以是來自另外一個給你簽發證書的不同 CA 的 SKPI 指紋。

在這個問題上還有一種更安全的方法,就是事先創建好至少三個獨立的公鑰(使用 OpenSSL,參見此頁 了解 Javascript OpenSSL 命令生成器),並將其中兩個備份到一個安全的地方,離線存儲、不要放到網上。

為這三個證書創建 SPKI 指紋並固定它們,然後僅使用第一個作為當前的證書。當需要時,你可以使用備份密鑰之一。不過你需要讓 CA 給你做簽名來生成證書對,這可能需要幾天,依你的 CA 的工作情況而定。

對於 HPKP 來說這沒有問題,因為我們使用的是公鑰的 SPKI 哈希,而不是證書。失效或不同的 CA 簽名鏈並不影響。

如果你按照上述方法生成並安全存儲了至少三個獨立的密鑰,並固定它們,也可以防止你的 CA 撤銷你的網站證書並簽發一個假證書時出現問題。

SPKI 指紋

可以使用如下的 OpenSSL 命令來生成 SPKI 指紋,它出現在 RFC 草案 中:

openssl x509 -noout -in certificate.pem -pubkey | 
openssl asn1parse -noout -inform pem -out public.key;
openssl dgst -sha256 -binary public.key | openssl enc -base64

結果:

klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY=

上面輸入的 certificate.pem 文件是本站(https://raymii.org)的證書鏈中第一個證書。(在寫本文時COMODO RSA Domain Validation Secure Server CA, 序列號 2B:2E:6E:EA:D9:75:36:6C:14:8A:6E:DB:A3:7C:8C:07 )。

你也需要同樣對你的另外兩個備份公鑰生成指紋。

故障

在寫本文時(2015/1),唯一支持 HPKP 的瀏覽器(chrome)有一個嚴重的問題:Chrome 並不能夠區分 HSTS 和 HPKP 響應頭中的 max-age 和 includeSubdomains 參數。也就是說,如果你的 HSTS 和 HPKP 設置了不同的 max-age 和 includeSubdomains 參數,它們會互相搞亂。關於這個故障的更多信息參見:https://code.google.com/p/chromium/issues/detail?id=444511。感謝 Scott Helme(https://scotthelme.co.uk)發現並告訴我這個 Chromium 項目的問題。

Web 伺服器配置

下面你可以看到三個主流 Web 伺服器的配置方法。這只是一個 HTTP 響應頭,絕大多數 Web 伺服器都可以設置它。它只需要設置到 HTTPS 網站上。

下面的例子固定到 COMODO RSA Domain Validation Secure Server CA 及備份的 Comodo PositiveSSL CA 上,30天失效期,包括所有的子域。

Apache

編輯你的 Apache 配置文件(如 /etc/apache2/sites-enabled/website.conf 或 /etc/apache2/httpd.conf),並添加下列行到你的 VirtualHost 中:

# 如需要,載入 headers 模塊。
LoadModule headers_module modules/mod_headers.so

Header set Public-Key-Pins "pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="633lt352PKRXbOwf4xSEa1M517scpD3l5f79xMD9r9Q="; max-age=2592000; includeSubDomains"

Lighttpd

Lighttpd 更簡單一些,將下列行添加到你的 Lighttpd 配置文件(如 /etc/lighttpd/lighttpd.conf):

server.modules += ( "mod_setenv" )
$HTTP["scheme"] == "https" {
    setenv.add-response-header  = ( "Public-Key-Pins" => "pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="633lt352PKRXbOwf4xSEa1M517scpD3l5f79xMD9r9Q="; max-age=2592000; includeSubDomains")
}

NGINX

NGINX 的配置更簡短。添加以下行到你的 HTTPS 配置的 server 塊中:

add_header Public-Key-Pins 'pin-sha256="klO23nT2ehFDXCfx3eHTDRESMz3asj1muO+4aIdjiuY="; pin-sha256="633lt352PKRXbOwf4xSEa1M517scpD3l5f79xMD9r9Q="; max-age=2592000; includeSubDomains';

報告功能

HPKP 報告功能允許瀏覽器報告任何違例給你。

如果你在響應頭中添加了附加的 report-uri="http://example.org/hpkp-report" 參數,並用該 URI 處理接收到的數據的話,客戶端會在發現違例時發送報告給你。這個報告是以 POST 方式發送到你指定的 report-uri 上,並以類似下面的 JSON 格式:

{
    "date-time": "2014-12-26T11:52:10Z",
    "hostname": "www.example.org",
    "port": 443,
    "effective-expiration-date": "2014-12-31T12:59:59",
    "include-subdomains": true,
    "served-certificate-chain": [
        "-----BEGINCERTIFICATE-----nMIIAuyg[...]tqU0CkVDNxn-----ENDCERTIFICATE-----"
    ],
    "validated-certificate-chain": [
        "-----BEGINCERTIFICATE-----nEBDCCygAwIBA[...]PX4WecNxn-----ENDCERTIFICATE-----"
    ],
    "known-pins": [
        "pin-sha256="dUezRu9zOECb901Md727xWltNsj0e6qzGk"",
        "pin-sha256="E9CqVKB9+xZ9INDbd+2eRQozqbQ2yXLYc""
    ]
}

非強制,只報告

HPKP 也可以設置為非強制的,可以使用 Public-Key-Pins-Report-Only 來只發送違例報告給你。

這樣可以讓你在網站不可訪問或 HPKP 配置不正確時不固定,之後你可以將這個響應頭改為 Public-Key-Pins 來強制固定。

via: https://raymii.org/s/articles/HTTP_Public_Key_Pinning_Extension_HPKP.html

作者:Remy van Elst 譯者:wxy 校對:wxy

本文由 LCTT 原創翻譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    這個站點使用 Akismet 來減少垃圾評論。了解你的評論數據如何被處理

    More in:Linux中國

    Linux中國

    捐贈 Let's Encrypt,共建安全的互聯網

    隨著 Mozilla、蘋果和谷歌對沃通和 StartCom 這兩家 CA 公司處罰落定,很多使用這兩家 CA 所簽發證書的網站紛紛尋求新的證書籤發商。有一個非盈利組織可以為大家提供了免費、可靠和安全的 SSL 證書服務,這就是 Let's Encrypt 項目。現在,它需要您的幫助
    Linux中國

    關於Linux防火牆iptables的面試問答

    Nishita Agarwal是Tecmint的用戶,她將分享關於她剛剛經歷的一家公司(印度的一家私人公司Pune)的面試經驗。在面試中她被問及許多不同的問題,但她是iptables方面的專家,因此她想分享這些關於iptables的問題和相應的答案給那些以後可能會進行相關面試的人。 所有的問題和相應的答案都基於Nishita Agarwal的記憶並經過了重寫。 嗨,朋友!我叫Nishita Agarwal。我已經取得了理學學士學位,我的專業集中在UNIX和它的變種(BSD,Linux)。它們一直深深的吸引著我。我在存儲方面有1年多的經驗。我正在尋求職業上的變化,並將供職於印度的P
    Linux中國

    Lets Encrypt 已被所有主流瀏覽器所信任

    旨在讓每個網站都能使用 HTTPS 加密的非贏利組織 Lets Encrypt 已經得了 IdenTrust的交叉簽名,這意味著其證書現在已經可以被所有主流的瀏覽器所信任。從這個裡程碑事件開始,訪問者訪問使用了Lets Encrypt 證書的網站不再需要特別配置就可以得到 HTTPS 安全保護了。 Lets Encrypt 的兩個中級證書 ...