天天給 App 抓包,還不懂 HTTP 代理嗎?
一、序
有段時間沒寫 HTTP 協議相關的文章了,突然發現文章選題池里, 《實用 HTTP》 系列中還躺了個 HTTP 代理的主題沒有寫,那今天就來聊聊 HTTP 代理吧。
在 HTTP 協議中,最基礎的就是請求和響應的報文,而報文又由報文頭和報文實體組成。大多數 HTTP 協議的使用場景,都是依賴設置不同的 HTTP 請求/響應 的 Header 來實現的。
既然要說到代理,先提兩個問題來當主線,從問題出發講解 HTTP 代理。
- 抓包工具是如何實現 HTTP 抓包的。
- 對于 HTTPS 流量,不安裝證書的情況下,通過抓包工具,請求和響應依然正常。
今天說的 HTTP 代理,更多的是一種抽象概念,其中的原理才是最關鍵的。
二、HTTP 代理
2.1 什么 HTTP 代理?
說到 HTTP 代理,作為客戶端開發,最熟悉的就是使用 Fiddler、Charles 等工具進行抓包時,需要在手機上掛個代理,來方便我們排查一些網絡問題,這只是代理眾多使用場景中的一個。
實際上,HTTP 代理(Web 代理)是一種存在于網絡中間的實體,可以提供各種功能。如果沒有 HTTP 代理,客戶終端就要直接與終端服務器進行交互。而有了 HTTP 代理后,客戶終端就可以與代理通信,然后由代理代表客戶端與服務器進行交互。
HTTP 代理算是最容易理解的一個 HTTP 協議概念,它和我們的生活最貼近。在我們的生活中,存在各種代辦的服務。
例如你和女友準備出國游,一些不免簽的國家,就需要提前辦理簽證。我們不熟悉自然覺得流程很復雜,這時就可以選擇交由旅行社來代理辦理簽證,你只需要根據對方提供的清單準備材料,就可以很方便的獲得簽證。在這個過程中,你節省了時間,而旅行社賺了你一點錢。
代理服務,就是代理客戶端完成事務處理的中間人,它接管客戶端的事務,代替客戶端與服務端交互。
代理服務是一個抽象的中間實體,可以存在網絡的各個中間點,瀏覽器、路由器、代理服務器、Web 服務器的反向代理等,
2.2 HTTP 代理的分類
從最熟悉的抓包工具說起,Fiddler、Charles 這種抓包工具,封裝的都非常好,哪怕我們完全不理解 HTTP 代理的細節,簡單配置就可以使用。
在使用過程中,你會發現兩種場景:
- 對于 HTTP 協議請求,可以直接顯示請求/響應報文的細節
- 對于 HTTPS ,如果沒有導入證書,請求依然可以發送至服務器,并且也可以正常返回數據,但是不會顯示報文細節。
在沒有導入證書的情況下,HTTPS 請求我們無法獲知細節,但是并不影響我們的請求和響應。
這個兩種不同的表現,也對應了兩種不同的 HTTP 代理:
- 普通代理。基于修訂后的 RFC 2616 在 HTTP/1.1 中被定義。這種代理扮演的是「中間人」的角色。對客戶端來說,它是服務端,而對真正的服務端來說,它又是客戶端,它就是負責在兩端之間傳遞 HTTP 報文。
- 隧道代理。這種一種基于 TCP 協議的隧道傳輸代理,它通過 HTTP 協議的 CONNECT 方法完成通信,以 HTTP 的方式,實現任意基于 TCP 的應用層協議代理。
接下來我們就分別對這兩種代理進行講解。
2.3 普通代理
普通代理,理解起來并不復雜,它是網絡中的中間實體,位于客戶端和服務端之間,扮演「中間人」的角色,在兩端之間來回傳遞報文。
這個「中間人」左手牽著客戶端,右手牽著服務端,在收到客戶端發送的請求報文時,需要正確的處理請求和連接狀態,同時向服務器發送新的請求,在收到響應后,將響應結果包裝成一個響應體返回給客戶端。
在普通代理的流程中,代理兩端都是有可能察覺不到「中間人」的存在。
舉個例子,我們要訪問 A 網站,實際上我們是向代理服務器發送請求,而代理服務器又再向 A 網站發起請求,最終將響應體通過代理服務器,返回給我們。在我們的角度,我們正常的向一個網站服務器發起請求,并且對方也返回給我們正確的數據,在這個過程中,我作為客戶端,會認為代理服務器就是 A 網站的服務器,而 A 網站的服務器,又認為代理服務器是一個真實的用戶。
這里說到,代理服務器作為「中間人」是可以隱藏自己的存在,但是如果我們作為一個“守規矩”的代理服務器,想要將客戶端的 IP 傳遞給服務端,可以通過 X-Forwarded-IP 這個自定義的 Header,來告訴服務端真正的客戶端 IP 地址。
HTTP 協議作為一種松散的協議,服務器在接收到 X-Forwarded-IP 這個請求頭時,是無法驗證其真偽的。它可能是代理服務器偽造的,也可能是真實的。所以服務端從 HTTP 頭部獲取 IP 時,就需要格外小心。
普通代理很好理解,但是它也有缺陷,它只適用于 HTTP 協議。
在普通代理模式下,所有請求響應的數據,對于代理這個「中間人」來說,都是透明并且可以任意操作,這就會帶來各種數據安全的隱患。
說到網絡數據安全,首先想到的就是 HTTPS,但是 HTTPS 這種證書認證的機制,又是中間人劫持的克星。
嚴格上來說,HTTPS 下不存在中間人攻擊,除非是人為的犯錯了,沒有對證書嚴格校驗,或者證書被泄露。
在普通的 HTTPS 請求中,服務端不驗證客戶端的證書,中間人可以作為客戶端與服務端完成 TLS 握手。
但是由于代理中間人沒有證書密鑰,也就無法偽造服務端和客戶端簡歷的 TLS 連接,這會導致請求失敗。
這個場景,對標到抓包工具的工作流程中,你會發現,如果想用 Charles(或Fiddler) 抓 HTTPS 的網絡數據包,就需要在手機上安裝一個 Charles 的 CA 證書,讓手機設備信任此證書,才可以完成抓包,此時走的就是普通代理的模式。
那換個角度,假如在手機上沒有安裝 Charles 提供的證書,也并沒有影響到請求和響應,Charles 只是無法解密 HTTPS 數據,這是如何做到的呢?
這就需要用到隧道代理。
2.4 隧道代理
隧道代理,又稱為 Web 隧道(Web tunnel),這種方式可以通過 HTTP 連接發送非 HTTP 流量,這樣可以在 HTTP 上捎帶其他協議的數據。
隧道代理是利用 HTTP 的 CONNECT 方法建立起來的。CONNECT 方法,最初并不是 HTTP/1.1 的核心規范,但卻是一種得到廣泛使用的擴展,它在 2014 年發布的 HTTP/1.1 修訂版中,才對 CONNECT 及隧道代理有了清晰的描述。
HTTP 隧道代理的工作流程是什么樣的?
一次普通的 HTTP 請求,Header 部分以連續的兩組 CRLF(\r\n)作為結束標記,如果后面還有內容,就是 Content 部分的內容,也稱為請求/響應體(Content),如果存在 Content 內容,就需要在 Header 中增加 Content-Length 來標記 Content 部分的長度。接收方(服務端)會根據這個長度來讀取數據。
CONNECT 報文的請求,是沒有 Content 部分的,只有 Request-Line 和 Header,他們僅供代理服務器使用,并不會傳遞給終端服務器。請求的 Header 部分一旦結束(兩組連續的 CRLF),后面的所有數據,都被視為應該轉發給終端服務器的數據,代理需要把他們無腦的直接轉發,并且不限制長度,直到從客戶端的 TCP 讀通道關閉。
CONNECT 的響應報文,在代理服務器和終端服務器建立連接后,可以向客戶端返回一個 200 Connect established 的狀態碼,以此表示和終端服務器的連接,建立成功。這個 200 Connect established 的 Header 部分一旦結束(兩組連續的 CRLF),后面所有的數據均為遠端服務器返回的數據,同理,代理服務器會直接轉發終端服務器的數據給客戶端,直到終端服務器的 TCP 讀通道關閉。
了解清楚 HTTP 隧道的工作流程之后,就知道 CONNECT 方法請求隧道網管創建一條到達任意目的服務器和端口的 TCP 連接,并對客戶端和服務端之間的后續數據,進行無腦的盲轉發。
通過隧道代理,代理服務器不再作為中間人,不再需要改寫瀏覽器的請求,而是把瀏覽器和終端服務器的數據,原樣轉發,這樣瀏覽器就可以直接和終端服務器進行 TLS 握手,并傳輸加密的數據。
2.4 導入證書后,Charles 抓 HTTPS 流程
Charles 作為抓包工具,在手機上沒有導入證書的時候,是通過隧道代理來保證數據的傳輸。一旦導入證書之后,Charles 就又切換到普通代理的工作模式,此時我們就可以解析 HTTPS 的流量數據。
這里簡單說一下原理。
在導入證書后,請求時手機就會信任 Charles 偽造的證書,而 Charles 又偽裝成真實的客戶端與服務端之間建立正確的 TLS 連接。此時,Charles 作為「中間人」,兩端的 TLS 流量都是可以被解密的。
三、總結時刻
到這里就了解清楚 HTTP 代理的細節,其實很抽象的概念,也很好理解。
簡單來說,HTTP 代理可以分為兩類,普通代理和隧道代理。
普通代理作為「中間人」存在,在一次請求中,客戶端明文請求代理服務器,在收到請求后,代理服務器又明文去請求終端服務器。在這整個過程中,數據都是明文傳輸,中間人可以對其中傳遞的數據進行改寫,這就是著名的中間人攻擊,可見其有多不安全。
這就引申出了支持 HTTPS 的隧道代理,此時代理服務器就不再作為中間人,無法改寫客戶端的請求,而僅僅是在建立連接后,將客戶端的請求,通過建立好的隧道,無腦的轉發給終端服務器。
【本文為51CTO專欄作者“張旸”的原創稿件,轉載請通過微信公眾號聯系作者獲取授權】