web 安全是一項系統工程,任何細微疏忽都可能導緻整個安全壁壘土崩瓦解。拿 https 來說,它的「内容加密、資料完整性、身份認證」三大安全保證,也會受到非法根證書、服務端配置錯誤、ssl 庫漏洞、私鑰被盜等等風險的影響。很多同學認為隻要通路的網站位址前有一把小綠鎖就絕對安全,其實不然。本文通過介紹三種最正常的 https 流量解密方法及原理,淺談一下 https 的安全風險。

<a></a>
man-in-the-middle(中間人,簡稱為 mitm),能夠與網絡通訊兩端分别建立連接配接,交換其收到的資料,使得通訊兩端都認為自己直接與對方對話,事實上整個會話都被中間人所控制。簡而言之,在真正的服務端看來,中間人是用戶端;而真正的用戶端會認為中間人是服務端。
本文主要讨論 https 中間人,簡單示意如下:
<code>server <---> local proxy <---> browser</code>
<code>^ ^</code>
<code>https(1) https(2)</code>
上述 https(1) 連接配接,是中間人冒充用戶端,與服務端建立的連接配接,由于 https 服務端一般不認證用戶端身份,這一步通常沒有問題。而對于 https(2) 連接配接來說,中間人想要冒充服務端,必須擁有對應域名的證書私鑰,而攻擊者要拿到私鑰,隻能通過這些手段:
去網站伺服器上拿;
從 ca 處簽發證書;
自己簽發證書。
要防範前兩點,需要網站做好各個方面的安全防護,從主機安全到網站安全(避免私鑰被盜),從域名解析安全到域名郵箱安全(避免攻擊者重簽證書)。而攻擊者自己簽發的證書,無法通過系統内置根證書的驗證,預設無法用于中間人攻擊。
對于 fiddler 這一類調試工具來說,能夠解密 https 流量的關鍵在于他們會往系統受信任的根證書清單導入自己的證書,這樣他們的自簽證書就能被浏覽器信任。進入 fiddler 設定中的「https」tab,勾選相關功能後,就可以順利解密和修改 https 流量。這時在浏覽器中可以看到這樣的證書鍊:
如果你擁有 https 網站的加密私鑰,可以用來解密這個網站的加密流量;
某些浏覽器支援将 tls 會話中使用的對稱密鑰儲存在外部檔案中,可供 wireshark 加密使用。
那篇文章介紹了第二種方案,本文簡單介紹第一種。
打開 wireshark 的 ssl 協定設定,參考下圖,把 ip、端口、協定和證書私鑰都配上(私鑰必須存為 pem 格式):
然後通路私鑰對應的網站,可以看到流量已被解密:
截圖中的加密資料是以 http/1 傳輸的,這種方式能解密 http/2 流量嗎?結論是:不能!具體原因下面慢慢分析。
我們知道,tls 握手階段需要進行密鑰交換和服務端認證這兩個重要的操作,密鑰交換是為了在不安全資料通道中産生一個隻有通信雙方知道的共享密鑰 premaster secret,進而生成 master secret 以及後續對稱加密 session key 和 mac key。而用戶端進行服務端認證的目的是確定連接配接到擁有網站私鑰的合法伺服器。
最常見的密鑰交換方式是 rsa,下面這張圖清晰的描述了這個過程:
<a href="https://blog.cloudflare.com/keyless-ssl-the-nitty-gritty-technical-details/">圖檔來源</a>
client random 和 server random 明文傳輸,中間人可以直接檢視。用戶端生成 premaster secret 後,用服務端證書公鑰加密後發送,如果服務端擁有對應的私鑰,就可以成功解密得到 premaster secret。這時,用戶端和服務端擁有相同的 client random、server random 和 premaster secret,可以各自算出相同的後續所需 key。
可以看到,這種方式合并了密鑰交換和服務端認證兩個步驟,如果服務端能解密 premaster secret,也就意味着服務端擁有正确的私鑰。中間人沒有私鑰,無法得到 premaster secret,也就無法解密後續流量。
對于 wireshark 來說,配置某個網站的私鑰後,能解密這個網站「使用 rsa 進行密鑰交換」的加密流量就很容易了解了。
顯然,rsa 密鑰交換有一個很大的問題:沒有前向安全性forward secrecy。這意味着攻擊者可以把監聽到的加密流量先存起來,後續一旦拿到了私鑰,之前所有流量都可以成功解密。
實際上,目前大部分 https 流量用的都是 ecdhe 密鑰交換。ecdhe 是使用橢圓曲線(ecc)的 dh(diffie-hellman)算法。下圖是 dh 密鑰交換過程:
上圖中的 server dh parameter 是用證書私鑰簽名的,用戶端使用證書公鑰就可以驗證服務端合法性。相比 rsa 密鑰交換,dh 由傳遞 premaster scret 變成了傳遞 dh 算法所需的 parameter,然後雙方各自算出 premaster secret。
對于這種情況,由于 premaster secret 無需交換,中間人就算有私鑰也無法獲得 premaster secret 和 master secret。也就是說 wireshark 無法通過配置 rsa private key 的方式解密「使用 ecdhe 進行密鑰交換」的加密流量。當然,使用 ecdhe 後,雖然中間人拿到私鑰也無法解密之前的流量,但他可以實施 mitm 攻擊來解密之後的流量,是以私鑰還是要保管好。
相比 rsa 既可以用于密鑰交換,又可以用于數字簽名;ecc 這邊就分得比較清楚了:ecdhe 用于密鑰交換,ecdsa 用于數字簽名。也就是目前密鑰交換 + 簽名有三種主流選擇:
rsa 密鑰交換、rsa 數字簽名;
ecdhe 密鑰交換、rsa 數字簽名;
ecdhe 密鑰交換、ecdsa 數字簽名;
以下是使用這三種密鑰交換方式的網站在 chrome 中的截圖:
firefox 和 chrome 都會在系統環境變量存在 <code>sslkeylogfile</code> 檔案路徑時,将每個 https 連接配接産生的 premaster secret 或 master secret 存下來。有了這個檔案,wireshark 就可以輕松解密 https 流量,即使是使用了 ecdhe 這種具有前向安全性的密鑰交換,如下圖:
<code>sslkeylogfile</code> 檔案記錄的是 https 資料傳輸中最重要的加密資訊,如果不是出于調試目的,一般也沒人會主動配置這個環境變量,是以這個方案基本不會對 https 安全性産生影響。
rsa 密鑰交換沒有前向安全性,這意味着一旦私鑰洩漏,之前所有加密流量都可以解開。為此,網站方需要啟用使用 ecdhe 作為密鑰交換的 ciphersuite,或者直接使用 ecc 證書;使用者方需要棄用不支援 ecdhe 的古董作業系統及浏覽器。
對于浏覽器而言,https 毫無秘密,通過浏覽器生成的 <code>sslkeylogfile</code> 檔案,wireshark 可以輕松解密 https 流量。另外,如果浏覽器被安裝惡意擴充,即使通路安全的 https 網站,送出的資料一樣可以被截獲。這種用戶端被攻擊者控制引發的安全問題,無法通過 https 來解決。
本文來自雲栖社群合作夥伴“linux中國”
原文釋出時間為:2013-04-02.