HTTP代理


HTTP代理存在兩種形式:

第一種是 RFC 7230 - HTTP/1.1: Message Syntax and Routing(即修訂后的 RFC 2616,HTTP/1.1 協議的第一部分)描述的普通代理。這種代理扮演的是「中間人」角色,對於連接到它的客戶端來說,它是服務端;對於要連接的服務端來說,它是客戶端。它就負責在兩端之間來回傳送 HTTP 報文。

第二種是 Tunneling TCP based protocols through Web proxy servers(通過 Web 代理服務器用隧道方式傳輸基於 TCP 的協議)描述的隧道代理。它通過 HTTP 協議正文部分(Body)完成通訊,以 HTTP 的方式實現任意基於 TCP 的應用層協議代理。這種代理使用 HTTP 的 CONNECT 方法建立連接,但 CONNECT 最開始並不是 RFC 2616 - HTTP/1.1 的一部分,直到 2014 年發布的 HTTP/1.1 修訂版中,才增加了對 CONNECT 及隧道代理的描述,詳見 RFC 7231 - HTTP/1.1: Semantics and Content。實際上這種代理早就被廣泛實現。

本文描述的第一種代理,對應《HTTP 權威指南》一書中第六章「代理」;第二種代理,對應第八章「集成點:網關、隧道及中繼」中的 8.5 小節「隧道」。

第一種普通代理:

 

 

 

第二種隧道代理:HTTP 客戶端通過 CONNECT 方法請求隧道代理創建一條到達任意目的服務器和端口的 TCP 連接,並對客戶端和服務器之間的后繼數據進行盲轉發。

 

 

 

假如我通過代理訪問 A 網站,瀏覽器首先通過 CONNECT 請求,讓代理創建一條到 A 網站的 TCP 連接;一旦 TCP 連接建好,代理無腦轉發后續流量即可。所以這種代理,理論上適用於任意基於 TCP 的應用層協議,HTTPS 網站使用的 TLS 協議當然也可以。這也是這種代理為什么被稱為隧道的原因。對於 HTTPS 來說,客戶端透過代理直接跟服務端進行 TLS 握手協商密鑰,所以依然是安全的,下圖中的抓包信息顯示了這種場景:

wireshark_connect

可以看到,瀏覽器與代理進行 TCP 握手之后,發起了 CONNECT 請求,報文起始行如下:

CONNECT imququ.com:443 HTTP/1.1

對於 CONNECT 請求來說,只是用來讓代理創建 TCP 連接,所以只需要提供服務器域名及端口即可,並不需要具體的資源路徑。代理收到這樣的請求后,需要與服務端建立 TCP 連接,並響應給瀏覽器這樣一個 HTTP 報文:

HTTP/1.1 200 Connection Established

瀏覽器收到了這個響應報文,就可以認為到服務端的 TCP 連接已經打通,后續直接往這個 TCP 連接寫協議數據即可。通過 Wireshark 的 Follow TCP Steam 功能,可以清楚地看到瀏覽器和代理之間的數據傳遞:

wireshark_connect_detail

可以看到,瀏覽器建立到服務端 TCP 連接產生的 HTTP 往返,完全是明文,這也是為什么 CONNECT 請求只需要提供域名和端口:如果發送了完整 URL、Cookie 等信息,會被中間人一覽無余,降低了 HTTPS 的安全性。HTTP 代理承載的 HTTPS 流量,應用數據要等到 TLS 握手成功之后通過 Application Data 協議傳輸,中間節點無法得知用於流量加密的 master-secret,無法解密數據。而 CONNECT 暴露的域名和端口,對於普通的 HTTPS 請求來說,中間人一樣可以拿到(IP 和端口很容易拿到,請求的域名可以通過 DNS Query 或者 TLS Client Hello 中的 Server Name Indication 拿到),所以這種方式並沒有增加不安全性。

 

HTTP代理和HTTPS代理的區別?

HTTP和HTTPS代理服務器,一般指的是代理服務器支持HTTPS協議和HTTP協議,
如果請求的URL是http的,使用HTTP代理服務器,客戶端->代理服務器->服務器之間數據都是明文的,不安全的。如果請求的URL是https,且代理服務器支持https協議,那么使用代理服務器時,代理服務器一般會使用CONNECT method(隧道模式,客戶端和代理服務器之間建立隧道進行通信)數據是安全的。
HTTP代理有多種做法,通常使用CONNECT method,通過proxy建立一條隧道(隧道代理),這樣proxy無法解密數據;此外,還有一種類似於中間人攻擊的代理手法。
 
connect 建立過程都是明文的,但是 CONNECT 請求只需要提供域名和端口,這樣子保證了請求的安全性,真正的數據需要等到TLS 握手成功后才用加密發送出去。
也就是說,使用了proxy后,代理服務器和客戶端之間的通信是明文的,但是兩者之間交換的只有域名和端口,proxy對客戶端傳過來的數據做解析取出域名和端口,跟服務器建立連接,建立好連接后給客戶端返回,此時就算是建立好隧道了,建立好隧道后,客戶端直接在隧道里跟服務器通信,此時proxy只是做個轉發,不會再處理客戶端的數據

connect方法
http 1.1定義了8種方法,connect為其中之一,HTTP/1.1協議中預留給能夠將連接改為管道方式的代理服務器。通常用於SSL加密服務器的鏈接(經由非加密的HTTP代理服務器)。
並非所有的http隧道支持connect方法,Http隧道分為兩種:
1  不使用CONNECT的隧道
不使用CONNECT的隧道,實現了數據包的重組和轉發。在Proxy收到來自客戶端的Http請求之后,會重新創建Request請求,並發送到目標服務器,。當目標服務器返回Response給Proxy之后,Proxy會對Response進行解析,然后重新組裝Response,發送給客戶端。所以,在不使用CONNECT方式建立的隧道,Proxy有機會對客戶端與目標服務器之間的通信數據進行窺探,而且有機會對數據進行串改。
 
2  使用CONNECT的隧道
而對於使用CONNECT的隧道則不同。當客戶端向Proxy發起Http CONNECT Method的時候,就是告訴Proxy,先在Proxy和目標服務器之間先建立起連接,在這個連接建立起來之后,目標服務器會返回一個回復給Proxy,Proxy將這個回復轉發給客戶端,這個Response是Proxy跟目標服務器連接建立的狀態回復,而不是請求數據的Response。在此之后,客戶端跟目標服務器的所有通信都將使用之前建立起來的建立。這種情況下的Http隧道,Proxy僅僅實現轉發,而不會關心轉發的數據。這也是為什么在使用Proxy的時候,Https請求必須首先使用Http CONNECT建立隧道。因為Https的數據都是經過加密的,Proxy是無法對Https的數據進行解密的,所以只能使用CONNECT,僅僅對通信數據進行轉發。

 

用curl對使用代理和不使用代理做分析:

使用代理,隧道模式

curl -v -I   https://sp.com.cn/v
* Uses proxy env variable https_proxy == 'http://127.0.0.1:808'
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 808 (#0)
* allocate connect buffer!
* Establish HTTP proxy tunnel to xx
> CONNECT sp.com.cn:443 HTTP/1.1
> Host: xx
> User-Agent: curl/7.61.0
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 OK
HTTP/1.1 200 OK
< Date: Thu, 29 Apr 2021 03:29:45 GMT
Date: Thu, 29 Apr 2021 03:29:45 GMT
< Transfer-Encoding: chunked
Transfer-Encoding: chunked
* Ignoring Transfer-Encoding in CONNECT 200 response
<

* Proxy replied 200 to CONNECT request
* CONNECT phase completed!
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* CONNECT phase completed!
* CONNECT phase completed!
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384

不使用代理: 

curl -v -I   https://sp.com.cn/v
*   Trying 121.46.8.134...
* TCP_NODELAY set
* Connected to sp.com.cn  port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: none
  CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Client hello (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES256-GCM-SHA384

  

以上可以看使用隧道模式的代理和不使用代理,都會進行TLS握手,隧道模式的代理是安全的。

 

參考資料:

https://imququ.com/post/x-forwarded-for-header-in-http.html

http://www.verydoc.net/http/00004337.html

https://lilywei739.github.io/2017/01/25/principle_for_http_https.html

https://www.cnblogs.com/a3192048/p/12241059.html

https://blog.csdn.net/dashenpanguge/article/details/105290116

《HTTP 權威指南》

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM