http 是 SSL/TLS 協(xié)議之上的 HTTP 協(xié)議,現(xiàn)在我們使用的主要是 TLS v1.2、TLS v1.3,如果想深入的了解 TLS 協(xié)議的細(xì)節(jié),客戶端與服務(wù)端是如何交互的,最好的學(xué)習(xí)方法是使用抓包工具,捕獲網(wǎng)絡(luò)數(shù)據(jù)包,基于這些真實(shí)的數(shù)據(jù)包能夠有一些直觀的感受。例如:Wireshark,它可以捕獲 HTTP、TCP、TLS 等各種網(wǎng)絡(luò)協(xié)議數(shù)據(jù)包,是我們學(xué)習(xí)的好工具。
但是 http 在握手過程中,密鑰規(guī)格變更協(xié)議發(fā)送之后所有的數(shù)據(jù)都已經(jīng)加密了,有些細(xì)節(jié)也就看不到了,如果常規(guī)的使用 Wireshark 這些工具是無(wú)法捕獲到解密后的數(shù)據(jù)的,下面讓我們先從 TLS v1.2 開始。
TLS v1.2 抓包
tcpdump 是一個(gè) Unix/Linux 下的網(wǎng)絡(luò)數(shù)據(jù)采集分析工具,也是我們常說的抓包工具。另一個(gè)與之類似的是 Wireshark,兩者區(qū)別是 Wireshark 提供了客戶端圖形界面化展示,更多的用在客戶端,而 tcpdump 是一個(gè)命令行工具,可用于服務(wù)端抓取數(shù)據(jù)輸出到指定文件,并且 tcpdump 輸出的 .cap 文件是可以被 Wireshark 解析的。
我通常更喜歡在命令抓取數(shù)據(jù),讓我們一起看看兩者結(jié)合如何使用,首先我們用 tcpdump 抓取一個(gè)網(wǎng)絡(luò)數(shù)據(jù)包。
-i:指定網(wǎng)卡,默認(rèn)只監(jiān)聽第一個(gè)網(wǎng)絡(luò)接口,通常是 en0,需要注意 localhost 不會(huì)走這個(gè)網(wǎng)絡(luò)接口,通過 ifconfig 命令在本機(jī)查看。
-v:顯示更多的詳細(xì)信息。
host www.imooc.com and port 443:過濾指定地址、端口的數(shù)據(jù)(這里之所以抓取 immoc 是因?yàn)榭戳讼缕?TLS 協(xié)議是 v1.2,協(xié)議不同抓包的結(jié)果也是不同的,下面會(huì)介紹 TLS v1.3)。
-w:將數(shù)據(jù)報(bào)文輸出到指定文件。
# 首先監(jiān)視指定的地址
sudo tcpdump -i en0 -v 'host www.imooc.com and port 443' -w imooc-http.cap
# 再打開一個(gè)終端發(fā)起請(qǐng)求,響應(yīng)成功后關(guān)閉
curl http://www.imooc.com/
結(jié)合 Wireshark 工具使用,菜單欄選擇 “File” -> “Open” 打開生成的數(shù)據(jù)報(bào)文,可看到類似下面的輸出信息。

現(xiàn)在我們沒有解密抓取的 http 數(shù)據(jù),在 TLS v1.2 握手階段 Certificate 消息這個(gè)時(shí)候還是明文傳遞的,在 Change Cipher Spec 協(xié)議發(fā)送之后所有數(shù)據(jù)都是加密傳輸。其實(shí),TLS v1.2 如果我們不做 http 解密處理,握手階段也是可以做一些分析的,接下來的 TLS v1.3 又待如何呢?
TLS v1.3 抓包
TLS v1.3 協(xié)議相較于 TLS v1.2 要復(fù)雜些,要考慮客戶端/服務(wù)器(網(wǎng)站)是否同時(shí)支持 TLS v1.3?抓包工具是否支持?如何解密 http 加密后的數(shù)據(jù)?
現(xiàn)在已經(jīng)有很多網(wǎng)站支持 TLS 1.3 協(xié)議了,例如 Github、知乎等。抓包之前,最好還是先驗(yàn)證下客戶端與服務(wù)器是否都支持 TLS 1.3,如果僅一端支持還是會(huì)降級(jí)為 TLS 1.2 協(xié)議或更低的協(xié)議支持。
瀏覽器、OpenSSL 等的 TLS 支持情況請(qǐng)參考 http://wiki.mozilla.org/Security/Server_Side_TLS。
之前我通過 Chrome 瀏覽器測(cè)試 TLS 1.3 一直都很好用,但當(dāng)我在終端使用 **curl** --tlsv1.3 [http://www.github.com](http://www.github.com) 命令時(shí),卻報(bào)錯(cuò) curl: (4) LibreSSL was built without TLS 1.3 support,這與 curl 版本有關(guān),參考文章 Curl with TLSv1.3 and openSSL on macOS。
驗(yàn)證**網(wǎng)站(服務(wù)端)**的 TLS 1.3 支持情況,在 Chrome 開發(fā)者工具 -> Security 模塊查看。

以 Github 網(wǎng)站為例,終端執(zhí)行以下命令,開啟抓包準(zhǔn)備,之后瀏覽器輸入 http://github.com 抓取數(shù)據(jù)。
$ sudo tcpdump -i en0 -v 'host www.github.com and port 443' -w github-tls1-3.cap
$ curl http://www.github.com
以下為常規(guī)方法抓取到的數(shù)據(jù),在 Change Cipher Spec 協(xié)議之后的數(shù)據(jù)都已做加密處理,像握手過程中的 Certificate、Finished 這些消息是看不到的,此時(shí)看不到完整的握手過程是怎么樣的。

解密 http 數(shù)據(jù)
解密 http 數(shù)據(jù),需要借助 Wireshark 的功能實(shí)現(xiàn),目前有兩種方式:基于 RSA 密鑰協(xié)商算法在 Wireshark 中配置服務(wù)器私鑰、會(huì)話級(jí)別的密鑰文件。
Wireshark 中配置服務(wù)器私鑰這種方式需要獲取到證書中攜帶公鑰對(duì)應(yīng)的服務(wù)器私鑰,然而這種方式僅在協(xié)商密鑰為 RSA 算法時(shí)生效,它不具有前向安全保護(hù),一旦拿到服務(wù)器私鑰如果黑客記錄了之前的會(huì)話是可以破解的,RSA 協(xié)商密鑰算法在 TLS v1.3 已經(jīng)廢除了。
密鑰日志文件是 Firefox、Chrome 和 curl 等應(yīng)用程序在設(shè)置 SSLKEYLOGFILE 環(huán)境變量時(shí)生成的文本文件,它們的底層庫(kù)(NSS、OpenSSL 或 boringssl)會(huì)將每次會(huì)話密鑰寫入文件,隨后可以在 Wireshark 中配置此文件實(shí)現(xiàn)解密。
不同的操作系統(tǒng)和不同的瀏覽器操作上會(huì)有區(qū)別,可以參考這篇介紹 : Decrypt SSL traffic with the SSLKEYLOGFILE environment variable on Firefox or Google Chrome using Wireshark。
本文以 Mac 系統(tǒng),Chrome 瀏覽器介紹。在本地 Home 目錄下創(chuàng)建一個(gè) sslkeylog.log 文件,之后在終端以命令方式打開 Chrome 瀏覽器,攜帶 --ssl-key-log-file。
$ touch ~/sslkeylog.log
$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --ssl-key-log-file=/Users/{user}/sslkeylog.log
注意:--ssl-key-log-file 后面的路徑,最開始我是用的相對(duì)路徑 ~/sslkeylog.log 運(yùn)行之后一直失敗,錯(cuò)誤信息提示無(wú)法加載密鑰日志文件 ~/sslkeylog.log。后來解決方法是改成了絕對(duì)路徑 --ssl-key-log-file=/Users/{user}/sslkeylog.log 加載密鑰日志文件。
[10270:259:1106/140033.195135:ERROR:network_service_instance_impl.cc(738)] Failed opening SSL key log file: ~/sslkeylog.log
Wireshark 選擇 “Preferences” -> “Protocols” -> “TLS”,配置預(yù)主密鑰日志文件路徑。

之后,Wireshark 配置好過濾規(guī)則,可以抓包了。