HTTPS连接如何通过代理服务器: CONNECT方法

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 方法,但不同的是它只用来建立连接。具体工作流程如下:

  1. 客户端发送 CONNECT 请求到代理服务器:

    CONNECT example.com:443 HTTP/1.1
    Host: example.com
    Proxy-Connection: keep-alive
  2. 代理服务器收到请求后,会与目标服务器建立 TCP 连接,之后会返回给客户端:

    HTTP/1.1 200 Connection established

    代理服务器通常不会转发 CONNECT 请求本身到目标服务器

  3. 之后,代理服务器就变成了一个透明的 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 连接
  • 将两个连接桥接起来