使用 libcurl 等網絡庫通過 HTTP 代理訪問 HTTPS 資源時,會發現兩個 HTTP 響應。這背後是 RFC 2817 定義的 CONNECT 方法建立的隧道機制。
CONNECT host:port HTTP/1.1 給代理。host:port 建立 TCP 連接。200 Connection Established。Client Proxy Target Server │ │ │ ├─ CONNECT api.example.com:443 ─►│ │ │ ├─ TCP SYN ─────────────────────►│ │ │◄─ TCP SYN/ACK ────────────────┤ │◄── 200 Connection Established ┤ │ │ │ │ ├═══════ TLS ClientHello ══════════════════════════════════════►│ │ │ │ │◄═══════ TLS ServerHello ══════════════════════════════════════┤ │ │ │ │ (後續加密應用數據雙向透傳) │ │
// 伪代碼:libcurl/Chromium 等庫的處理邏輯
if (proxy && scheme == "https") {
// 1. 發送 CONNECT 請求
send_request("CONNECT " + host + ":" + port + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
(proxy_auth ? "Proxy-Authorization: ...\r\n" : "") +
"\r\n");
// 2. 讀取響應,必須是 2xx
response = read_response();
if (response.status < 200 || response.status >= 300)
throw ProxyConnectFailed();
// 3. 隧道建立,同一 socket 升級為 TLS
ssl_socket = tls_handshake(socket, host);
// 4. 發送真實的 HTTP 請求
ssl_socket.send("GET /path HTTP/1.1\r\nHost: " + host + "\r\n...\r\n");
}
| 特性 | 非 CONNECT | CONNECT 隧道 |
|---|---|---|
| 數據可見性 | 代理可見明文 | 代理僅見加密字節流 |
| 端口限制 | 通常僅 80/8080 | 可連接任意端口 |
| 風險 | 數據竊取、篡改 | 繞過防火牆、SSH/DB 連接隧道化 |
| 防禦 | 內容檢查 | 限制 CONNECT 目標端口 (僅 443)、認證、審計 |
200,第二個是 TLS 內的真實 HTTP 響應。CONNECT 是 HTTP/1.1 為 HTTPS 代理設計的隧道建立機制。