HTTP 1.1引入了HTTP tunnel,提供了支援任意流量的TCP隧道的能力。 HTTP proxy是一個中間人,是用戶端去請求代理,代理修改請求再去請求網站,proxy不能代理HTTPS請求,因為代理不可能獲得網站的私鑰。 HTTP tunnel 不需要改寫請求包,将C S之間的流量直接轉發,是以可以傳輸代理TLS加密的HTTPS流量。
HTTP tunnel使用CONNECT方法進行建立隧道連接配接通信。
HTTP tunnel是HTTP/1.1中引入的一個功能,主要為了解決明文的HTTP proxy無法代理跑在TLS中的流量(也就是https)的問題,同時提供了作為任意流量的TCP通道的能力。
HTTP tunnel的工作流程是什麼樣的?:
CONNECT封包沒有後面的負載部分,隻有Request-Line和header後面以兩個\r\n斷開,Request-Line和header均是由代理伺服器使用,不會發送到遠端伺服器。請求的header部分一旦結束(連續的兩組CRLF),後面所有的資料都被視為應該發給遠端伺服器(網站)的資料,代理需要把它們直接轉發,而且不限長度,直到從用戶端的TCP讀通道關閉。
響應同理:對于CONNECT封包的傳回值,代理伺服器在和遠端伺服器成功建立連接配接後,可以(标準說的是可以,但是一般都會)向用戶端(浏覽器)傳回任意一個2xx狀态碼,此時表示含義是和遠端伺服器建立連接配接成功,這個2xx傳回封包的header部分一旦結束(連續的兩組CRLF),後面所有的資料均為遠端伺服器傳回的資料,同理代理會直接轉發遠端伺服器的傳回資料給用戶端,直到從遠端伺服器的TCP讀通道關閉。
HTTP tunnel出來之前,HTTP proxy工作在中間人模式,即在一次請求中,用戶端(浏覽器)銘文的請求去請求代理伺服器。代理伺服器明文去請求遠端的伺服器(網站)。整個過程的請求響應内容(密碼cookie等)代理伺服器都是可見的。且使用HTTP proxy模式要求代理伺服器對請求封包進行适當修改,RFC2616 5.1.2中要求請求代理的封包中Request-URL使用絕對路徑,即以http開頭:
使用了代理後,發送的封包将變為:
代理從請求的第一行中得知要請求的目标是stackoverflow.com,端口為預設端口(80),将第一行改寫後,向網站伺服器發送請求:
因為:如果代理HTTPS流量,那麼就會變成浏覽器和代理握手跑TLS,代理拿到明文的請求封包,代理和網站握手跑TLS。但是代理沒有,也不可能有網站的私鑰證書,是以這麼做會導緻浏覽器和代理之間的TLS無法建立,證書校驗根本通不過。但是HTTP tunnel的出現解決了這個問題,代理伺服器不再作為中間人,不在用改寫請求。
其中相同的地方:
都能在請求中指明要請求的目标和端口。
都會建立能傳輸任何流量的TCP通道,代理伺服器對流量内容不關心。
都是在封包前部的描述資訊結束後,将後續所有資料視為轉發的用戶端和服務端資料,直到通道關閉。
都可以進行用戶端的身份驗證,而且有多重身份驗證協定可選。
不同的地方:
SOCKS5的封包無論請求還是傳回,内容均是固定的。而CONNECT封包作為HTTP/1.1的封包之一,當然也包括了HTTP/1.1可以傳輸任何自定義header的功能,雖然一般代理不會響應CONNECT封包上的非标準header,但是自己實作一個用戶端和伺服器通過header傳輸一些其它資料也是符合标準的。
SOCKS5 request封包中的address,根據address type(ATYP)位元組的值,可以顯式聲明為IPv4位址、IPv6位址、域名(domain)。而CONNECT封包中的Request-URI根據RFC要求必須為authority形式(即沒有http://字首,隻包含host,以及可選的port,其中host和port要用":"分隔),也就是說CONNECT封包不會顯式的區分IP位址和域名,均作為host傳輸。
由于CONNECT封包還是http,是以也可以跑在TLS裡,也就是說用戶端和代理跑一層TLS,這一層裡面用戶端和遠端伺服器再跑一層TLS。這樣當代理伺服器需要使用者名密碼驗證,而驗證方式又是Basic時,可以通過TLS來保護代理請求封包中的明文使用者名密碼。
參考來源:https://www.zhihu.com/question/21955083/answer/142736329