HTTP/2 流量调试
當前主要可以通過瀏覽器和Wireshark等工具調試HTTP/2流量。
使用瀏覽器調試HTTP/2流量
HTTP/2 引入二進制分幀層(Binary Framing),將每個請求和響應分割為更小的幀,并對它們進行二進制編碼。與此同時,HTTP/2 沿用之前 HTTP/1.1中的絕大部分語義,上層應用基本上感知不到 HTTP/2 的存在。通過瀏覽器提供的網絡調試工具我們可以清晰地看到請求和響應的詳細信息。
對于Chromium瀏覽器,打開"更多工具(L) -> 開發者工具(D)",然后選中"Network",并選中要查看的文件,就可以清晰地看到HTTP/2請求及響應的信息了。如:
從上圖可以看到,HTTP/2資源的內容,與HTTP/1.1資源的內容相比,只有一些細微的變化,如所有的頭部字段名都是小寫的,引入了以":"開頭的偽首部字段等。
然而,瀏覽器的調試工具只能看到請求和響應的信息。對于連接建立、數據傳輸,及流控這樣的過程信息,瀏覽器的調試工具就顯得無能為力了。這些更細節的信息可以通過Wireshark來看。
使用 Wireshark 調試 HTTP/2 流量
盡管HTTP/2規范并沒有嚴格要求只能基于TLS傳輸HTTP/2流量,然而目前基于TLS傳輸HTTP/2已然成為事實的標準了。絕大部分提供HTTP/2服務器的網站都基于TLS來提供,常見的客戶端瀏覽器,如Chrome,Firefox更是完全不提供對明文傳輸的HTTP/2的支持。因而通過Wireshark調試HTTP/2流量最主要的即是解密HTTPS流量,進而借助Wireshark對HTTP/2數據的解析,看到客戶端與服務器之間詳細的幀交互過程。
Wireshark 的抓包原理是直接讀取并分析網卡數據,要想讓它解密 HTTPS 流量,有兩個辦法:1)如果擁有 HTTPS 網站的加密私鑰,可以用來解密這個網站的加密流量;2)某些瀏覽器支持將 TLS 會話中使用的對稱加密密鑰保存在外部文件中,可供 Wireshark 解密之用。
設置SSLKEYLOGFILE環境變量解密HTTPS流量
Firefox 和 Chrome 都支持生成上述第二種解密方式所需的文件,具體格式見 NSS Key Log Format。但只有設置了系統環境變量SSLKEYLOGFILE,Firefox 和 Chrome 才會生成該文件,它們將這個系統變量的值作為文件保存的路徑。先來加上這個環境變量(Ubuntu):
$ mkdir ~/sslkeylogfile && touch ~/sslkeylogfile/keylogfile.log$ echo -e '\nexport SSLKEYLOGFILE=~/sslkeylogfile/keylogfile.log' >> ~/.bash_profile && . ~/.bash_profile接著,通過選擇Edit -> Preferences... -> Protocols -> SSL打開Wireshark 的 SSL 配置面板(Ubunut版,Mac版通過Wireshark -> Preferences...打開首選項),在「(Pre)-Master-Secret log filename」選項中選擇SSLKEYLOGFILE文件,或輸入該文件的路徑。如下圖:
ssl_config.png
最好將「SSL debug file」也配上,這樣解密過程中的日志都會記錄下來,便于調試分析。
通過 終端 啟動 Firefox 或 Chrome(確保這些瀏覽器能讀取到環境變量):
$ chromium-browser這時再訪問 HTTPS 網站,sslkeylog.log文件中應該包含瀏覽器寫入的數據。如下面這樣:
$ cat ~/sslkeylogfile/keylogfile.logCLIENT_RANDOM 24103980248f266808400da7e48058f6c779b4b98fe8cae45981bafe7502b8ff 5e7e3a526fbf8c5a3567758f6aa412ea6c36c52d98e9a3dfde1d16f09714551bc64f62ca3cd9df2448b12dbf995d0b14 CLIENT_RANDOM 31c9cac267465543d6ea1ea358dd41fc9ed02aa8af45b0238b82e50915bc3360 dadf649c846b125dad5b1215e9d45ee34ba5241ecbc4856820ea7843177dc424a575fd788f007241c0252c718426dd92 CLIENT_RANDOM 36b8759c3bbb3df2645382240384675f1615f4a432ca7c58bf142776f752ee05 365c321e8d91834da7e8d44cbb963b2bc1b90f100a50fb7831bd5b9b7ec62d94c9a6de99da78c3c6aac93568cc675113 CLIENT_RANDOM 24a461fc4ae2295b81dc4eab6aff2e520e0fc2623091b249f59bfb46b1c3567d e2c8b46febbb61f0fa3e6a6857cd27fe95aa1a7616a522115488f35f30c3092d05b295cba99429d7c16d857cfb87953e CLIENT_RANDOM dcc1b0688d4dd99b3b5a4cacccfb9fa5d4861c439385abfb37cd4f98ed212091 3c6bb8767ddb4e6797880aadf5f59f39edaf15bc17c7a3632603803bffec45239261b9ae87d42495952c86c65158dbb4 CLIENT_RANDOM c96b42c46769d87fc06884da879a2f274047356ee3516f944aa0f37f72bbed0e 758e59ee207ff1667ee6643eb31d62aacb4a3fde3e39ab0654a003b0b015acd7e53de41ea754255e4bade1f25897643a CLIENT_RANDOM 766c0a2f84030be01513ffff1c36bff61872f0a8e039a40694eeee5b3a65c4ca efbdbc6cafdd32891df40daaa8d2c4778db889512c4e6ccd8a15a7f1e34ab55d7a657021eb9954883dc320cc632e8755 CLIENT_RANDOM b91cbe5fb40149006dbf95a74f1a8f9f0999a78c27dae42d169ca50521477c2c b3e9963f25598e9841ae58857ce13a891c22275f7f2d5c260446cba7355ccdcf41eeabe8f050350078ffe7a16a7c5219 CLIENT_RANDOM de8e0dbdc518459724cf5ed3cc09802c96fa558abe7c95ec4f0748700bc3e229 0cda6e9665758c54819cc00a09eb5f4249eb33519a16ae62911ffff090539aebd3138ebb4ee0ba7cab6630b3e255fffc CLIENT_RANDOM 6798fa4e2396f700f6309d55721badf73081ed2a8066db2f7bf652245c61076c 025a4679f2d399433a7dc9604f1b1a970dcc54b6da5166a188b061ece87cac1919e7b56be8455cf24ddffe1083694bb1 CLIENT_RANDOM d89d9e38c21af551d816f451ac3b25d29899f5623fa375f7c55897c06310e784 e9d56f1b084327850c96e30fa87488e7d83fcca7e5cd2200876aa8354d841d5432f339db04041fda5f79202c528e5399 CLIENT_RANDOM 5db78a4b93747b795867ed5800ed2f0c763d74f40fd9859e358689efcc3082c3 3e8edf030deae2d2ff78858b96d7525527e4bbdffe4caf62014a1977f008a7a9a6e96f08e07624a48ad45d45a3ef13c5 CLIENT_RANDOM 2902990ba00c5ad72fddf9a82fd78bdc40e347d423f5aaff71956780683b4df7 f51e107ad5db85ff16da162abb050482b196ffa0f99c2c1e834b73dd46454d322b53a85c14e5a266e05be20d19b1fd2a ......檢查無誤后,就可以開啟 Wireshark,選擇合適的網卡開始抓包。為了減少不必要的數據包對我們分析的干擾,我們可以只針對某個域名的TCP 443端口來抓包,以減少抓取的數據包的數量,如:
Capture Filter
新版 Wireshark (如我目前在用的Version 2.0.2) 在配置了 TLS 解密后,會自動識別并解析 HTTP/2 流量。訪問想要抓包的 HTTP/2 網站,就可以輕松看到想要的 HTTP/2 數據包了。如下圖:
wireshark_http2.png
這種方法也可以用在解密使用 HTTP/1 的 HTTPS 網站上。
每次都要從終端啟動瀏覽器還是挺麻煩的,我們也可以為GUI設置環境變量,以便于我們不在命令行終端啟動瀏覽器也可以解密HTTPS流量。方法是:
$ sudo echo -e '\nexport SSLKEYLOGFILE=~/sslkeylogfile/keylogfile.log' >> /etc/profile也可以通過其它任何個人偏好的編輯器為/etc/profile添加export那一行。更新了/etc/profile之后,注銷當前登錄并重新登錄。在GUI中啟動chromium瀏覽器,也可以通過Wireshark解密HTTPS流量了。不過要注意,這個設置對所有用戶均全局生效。為了系統安全最好在利用Wireshark調試HTTPS流量之后移除這一設置。
Wireshark就像一副眼鏡一樣,戴上它之后,可以讓我們對網絡世界發生的一切看得更加清楚,然而即使有了這樣強大好用的工具,要想對協議有真正的理解,仔細地閱讀協議規范文件也是必不可少的,關于HTTP/2協議的細節,可以參考HTTP2規范(RFC7540)、HPACK:HTTP/2的首部壓縮 (RFC7541)和應用層協議協商(ALPN)規范(RFC7301)。
導入服務器私鑰解密HTTPS流量
還可以通過為Wireshark導入服務器RSA私鑰來解密HTTPS流量。方法是選擇Edit -> Preferences... -> Protocols -> SSL打開Wireshark 的 SSL 配置面板,點擊"RSA keys list"后的"Edit..."按鈕:
rsa_key_record.png
添加一個RSA私鑰項,輸入適當的IP地址,端口,解密后的協議,及私鑰文件的路徑,其中私鑰必須存為 PEM 格式,這種格式的私鑰文件類似于下面這樣:
-----BEGIN RSA PRIVATE KEY----- MIIJKQIBAAKCAgEAw5JweP8ACiLHFAs9syY0yzdjJh3WQntcq1HM9xJXJrHRT1+n Als88+bh7HxmYbrYXtZhYEjW00wjmlB1Sy0biX17VS8SY7Ssx7XRRJXtovSd7nc8 KwZI2Rgh0e7PXCatwhEonCdlEZTEHQ9eTE8Acc9dH0BLml47sEJFxWgBYinCkrWt jRMR234CZRRqXUtmFgjUq5DcBignzYTAtzAi/1RxwjuNfYtSw6jx7mNCKt1Np3Bm ....... some 20-100 lines of base64 encoded data ............... +TtJwCHfBRGIyI3hGA1eBa8Lc3nhXPjUwtp7q+2gwpsq/25gt2tiUfSak7frhFal 9gP00/d9nJXwh2UR3G/oEsXWORfRUVAgjyzhXrrJ+uQJBgUVEZ1D0lI6qfdc -----END RSA PRIVATE KEY-----對于nginx服務器來說,通常通過ssl_certificate_key項配置的是站點私鑰,這個私鑰通常是在申請證書時,通過類似于如下這樣的方式產生:
$ openssl genrsa 4096 > domain.key關于私鑰格式的更多信息,可以參考Wireshark的SSL Wiki。
但這種方法對客戶端與服務器協商的加密套件有要求。如果加密套件的密鑰交換算法是ECDHE,也就是當前大多數HTTPS流量所選擇的算法,則解密HTTPS流量將失敗。可以通過Wireshark抓取的TLS握手的Server Hello消息來查看客戶端與服務器協商的加密套件:
Server Hello.png
客戶端與服務器協商加密套件的過程大體為,客戶端在其TLS握手的Client Hello消息的Cipher Suites字段中發送自己支持的加密套件。如通過curl訪問http2資源:
$ curl --http2 -v https://www.wolfcstech.com/可以看到curl支持的加密套件集:
client_cipher_suites.png
對于nginx,我們通過ssl_ciphers選項為其配置加密套件,如:
# https://github.com/cloudflare/sslconfig/blob/master/confssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;ssl_prefer_server_ciphers on;加密套件以":"分隔。服務器從為其配置的加密套件集中選擇排序最靠前的客戶端支持的加密套件。對于上面的服務器加密套件集配置,用curl訪問服務器,協商出來的加密套件為TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f),這種加密套件的密鑰交換算法正是ECDHE,也即不支持Wireshark加密的算法。
我們可以通過修改服務器的配置,以便Wireshark可以解密HTTPS流量。修改之后nginx服務器的加密套件配置為:
# https://github.com/cloudflare/sslconfig/blob/master/confssl_ciphers EECDH+CHACHA20:EECDH+CHACHA20-draft:RSA+AES128:EECDH+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;ssl_prefer_server_ciphers on;與前面那個配置相比,僅有的改動是對調了RSA+AES128和EECDH+AES128兩個加密套件的位置。再次通過curl訪問服務器,可以看到HTTP2流量被解密了:
curl_http2.png
這次協商的加密套件為TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c),其密鑰加密算法為RSA。
不過此時通過chrome瀏覽器訪問網站,就會發現頁面已經打不開了,如下圖所示:
cipher_suite_config_error_for_http2.png
仔細看的話,可以看到ERR_SPDY_INADEQUATE_TRANSPORT_SECURITY。這是由于為了安全性考慮,HTTP/2規范建立了加密套件黑名單,并強制要求HTTP/2服務不得配置這樣的加密套件。Chromium瀏覽器嚴格遵守HTTP/2規范,且在TLS協商階段,服務器選擇了加密套件黑名單中的TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c),因而連接直接被斷開了。通過Wireshark抓包來看:
http2_goaway.png
可見是HTTP2層,在與服務器建立連接之后,瀏覽器就立即發送GOAWAY幀斷開了連接。
然而curl似乎并沒有嚴格遵守HTTP/2規范。
是否可以通過為Wireshark添加RSA私鑰解密HTTPS流量的決定性因素,在于客戶端與服務器協商的加密套件,而不在于通過HTTPS傳輸的流量是HTTP/1.1的還是HTTP/2的。不過可以通過這種方法讓Wireshark解密的所有加密套件都已經進了HTTP/2規范的加密套件黑名單,因而對于符合規范的HTTP/2流量傳輸,都是無法通過這種方法來解密流量的。
判斷HTTP2是否啟用
如前面所述,在某些情況下,直接解密HTTP/2流量確實是難以實現的。而如果我們的需求僅僅是判斷HTTP/2是否啟用的話,則還是可以通過Wireshark實現的。
HTTP/2在TCP連接建立完成之后,TLS握手的過程中,會進行協議協商,以確定客戶端和服務器之間通信最終所用的應用層協議。這個協議協商協議成為ALPN。ALPN是TLS的特性,客戶端的SSL/TLS庫及使用SSL/TLS庫的模塊,如HTTP棧,只要支持這一擴展,在發送Client Hello消息時,就會帶上相關消息,如:
ALPN Extension
服務器的SSL/TLS庫及Web服務器如果能識別這一擴展,會在Server Hello消息中的相同擴展處放上服務器所選擇的用戶雙方通信的協議標識。如果為服務器配置了支持HTTP/2時,Server Hello消息的ALPN擴展值將為h2,否則將是http/1.1,如:
ALPS_01.png
因而盡管對于無法解密TLS流的HTTP/2流,在Wireshark中無法查看傳輸更多的細節過程,但還是可以通過Wireshark抓取到的Server Hello消息的ALPN擴展值判斷協議協商的結果。
參考文檔:
SSL - The Wireshark Wiki
Ubuntu系統環境變量詳解
使用 Wireshark 調試 HTTP/2 流量
三種解密 HTTPS 流量的方法介紹
為curl命令啟用HTTP2支持
總結
以上是生活随笔為你收集整理的HTTP/2 流量调试的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 非对称加密与证书
- 下一篇: 在C++中使用Protocol Buff