理解HTTP CONNECT通道
2018年8月12日

为了确保数据通信的安全,HTTPS 已广泛应用于互联网,浏览器与服务器之间的 HTTPS 通信都是加密的。然而当浏览器需要通过代理服务器发起 HTTPS 请求时,由于请求的站点地址和端口号都是加密保存于 HTTPS 请求头中的,代理服务器是如何既确保通信是加密的(代理服务器自身也无法读取通信内容)又知道该往哪里发送请求呢?为了解决这个问题,浏览器需要先通过明文 HTTP 形式向代理服务器发送一个 CONNECT 请求告诉它目标站点地址及端口号。当代理服务器收到这个请求后,会在对应的端口上与目标站点建立一个 TCP 连接,连接建立成功后返回一个 HTTP 200 状态码告诉浏览器与该站点的加密通道已建成。接下来代理服务器仅仅是来回传输浏览器与该服务器之间的加密数据包,代理服务器并不需要解析这些内容以保证 HTTPS 的安全性。

什么时候会用到 CONNECT 方法?

只有当浏览器配置为使用代理服务器时才会用到 CONNECT 方法。

CONNECT 通道建立流程

这里我们以 Fiddler 作为代理服务器,浏览器访问https://www.microsoft.com/作为例子:

  1. 首先浏览器向代理服务器发送 CONNECT 请求:

    CONNECT www.microsoft.com:443 HTTP/1.0
    User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
    Host: www.microsoft.com
    Content-Length: 0
    DNT: 1
    Connection: Keep-Alive
    Pragma: no-cache
    
  2. 代理服务器返回 HTTP 200 状态台码表示连接已建立:

    HTTP/1.0 200 Connection Established
    FiddlerGateway: Direct
    StartTime: 11:56:22.008
    Connection: close
    EndTime: 11:56:22.538
    ClientToServerBytes: 1416
    ServerToClientBytes: 1358
    
  3. 之后浏览器和服务器开始 HTTPS 握手并交换加密数据,Fiddler 作为代理服务器只负责传输彼此的数据包,并不能读取具体数据内容(除非开启了 Fiddler 的解密 HTTPS 的功能并安装 Fiddler 根证书)。从 Wireshark 抓包中可以看出,在第 12 贞HTTP/1.0 200返回后,浏览器就开始建立 TLS 连接了。

如何处理服务器错误 5xx?

如果代理服务器在连接目标站点时发生了错误如:DNS 主机解析失败、连接超时,那么该如何处理 CONNECT 请求呢?由于这些错误会导致代理服务器无法与站点建立起 TCP 连接,那么代理服务器理应返回相应的状态码给浏览器。

  • 502: Bad Gateway
  • 504: Gateway timeout

是否可以返回重定向 3xx?

实践中有一些代理服务器会在发生服务器无法连接后会针对 CONNECT 请求返回一个 302 重定向至一个定制过的错误页面来更好地告诉用户为什么无法显示该页面。虽然 HTTP 1.1 RFC 并没有规定 CONNECT 不能返回 3xx 重定向,但根据 302 RFC 定义:请求的资源暂时被移动到另一个路径,对一个无法连接的站点返回 302 是不合适的,该资源其实并不是被移至另一个路径,而是目标服务器根本无法连接。如果一个资源真的被移至另一个路径的话,那么只应该由站点亲自通过 HTTPS 加密数据来告诉浏览器,而不是通过代理服务器以明文形式在 CONNECT 请求中返回。

并且,对于 CONNECT 请求返回 302,多数现代浏览器并不会执行重定向命令,而是直接返回浏览器内置的错误页面。使用 Fiddler 的 Auto responder 功能可以模拟针对 CONNECT 请求返回 302。

HTTP CONNECT 请求:

CONNECT www.nonexistingwebsite.com:443 HTTP/1.1
Host: www.nonexistingwebsite.com:443
Proxy-Connection: keep-alive
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36

Fiddler HTTP Response:

HTTP/1.1 302 Redirect
FiddlerTemplate: True
Date: Fri, 25 Jan 2013 16:49:29 GMT
Location: http://www.fiddler2.com/sandbox/FormAndCookie.asp
Content-Length: 0

可以看出 Chrome、Firefox 和 IE 都不会执行这个 302 重定向,而是直接显示错误信息。

参考资料