
HTTPS连接如何通过代理服务器: CONNECT方法
使用 HTTP 代理来连接网络时,代理服务器会转发客户端的请求。但由于 HTTPS 需要先做 TLS 握手,使得代理服务器不能直接转发请求,而需要先建立连接才行。
HTTP 代理转发请求
代理服务器处理 HTTP 连接(即不经过 TLS 加密的)很简单。举例来说,客户端想访问 example.com,它会发送这个请求
GET http://example.com/index.html HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0
Proxy-Connection: keep-alive
这个请求会先经过代理服务器。代理会解析出目标 URL,然后再将这个请求完整的发送过去。收到响应后,再将响应转发到客户端。
HTTPS 连接
当套上 TLS 加密之后,问题变得复杂了起来。代理服务器不能直接转发客户端的请求,因为它不能代替客户端和服务器建立 TLS 连接,如果这样的话,客户端就会发现 TLS 证书错误。
CONNECT 方法解决了这个问题。它像 GET 一样是个 HTTP 方法,但不同的是它只用来建立连接。具体工作流程如下:
-
客户端发送 CONNECT 请求到代理服务器:
CONNECT example.com:443 HTTP/1.1 Host: example.com Proxy-Connection: keep-alive
-
代理服务器收到请求后,会与目标服务器建立 TCP 连接,之后会返回给客户端:
HTTP/1.1 200 Connection established
代理服务器通常不会转发 CONNECT 请求本身到目标服务器
-
之后,代理服务器就变成了一个透明的 TCP 隧道,无脑的转发 TCP 数据包。此时客户端就可以和服务器 TLS 握手并传输 HTTPS 数据。由于数据是加密的,代理服务器无法查看或修改通信内容。
sequenceDiagram participant Client participant Proxy participant Server Client->>Proxy: CONNECT example.com:443 Proxy->>Server: TCP Connection Server->>Proxy: Connection Established Proxy->>Client: HTTP/1.1 200 Connection established Note over Client,Server: TLS Handshake Note over Client,Server: Encrypted Communication
从上面的流程可以看到,CONNECT 方法其实是建立 TCP 隧道,并不是专为 TLS 设计的。所以其实任何 TCP 请求都可以通过这个隧道传输。
使用传输层的代理是否需要 CONNECT 方法
对于工作在传输层(TCP/UDP)的代理,如 SOCKS5 代理,是不需要 CONNECT 方法的。因为他们本身直接处理 TCP 和 UDP 连接,不需要理解应用层协议(如 HTTP)。
当客户端通过这些代理连接 HTTPS 网站时,代理服务器只需要:
- 接收客户端的连接请求
- 与目标服务器建立 TCP 连接
- 将两个连接桥接起来