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 权威指南》

 

posted @ 2021-05-06 20:00  cs_wu  阅读(1282)  评论(0编辑  收藏  举报