通过代理建立安全连接依赖 TLS 握手:客户端与最终服务器(视配置而定,可能是源站,也可能是代理本身)验证彼此身份,并协商加密参数以建立加密通信通道。该过程为跨网络通信的应用保证数据的机密性、完整性和真实性。
理解 TLS 握手
Transport Layer Security(TLS)协议是保障互联网通信安全的基础。它运行在传输层(TCP)之上,提供端到端加密与身份认证。TLS 握手是初始协商阶段:在交换应用数据之前,客户端与服务器就加密参数达成一致并建立安全会话。
TLS 握手的主要目标是:
* 身份认证:使用数字证书验证服务器(以及可选的客户端)身份。
* 密钥交换:安全地协商用于对称加密的共享密钥。
* Cipher suite 协商:选择加密、哈希和密钥交换算法。
直连 TLS 握手步骤
在不经过代理的直连中,TLS 握手过程如下:
- Client Hello:客户端发送
Client Hello消息发起握手。该消息包含:- 支持的 TLS 版本。
- 支持的 cipher suite 列表。
- 一段随机字节串(Client Random)。
- 支持的压缩方法。
- 用于虚拟主机的 Server Name Indication(SNI)。
- Server Hello:服务器以
Server Hello消息响应,并选定:- 要使用的 TLS 版本。
- 从客户端列表中选出的 cipher suite。
- 一段随机字节串(Server Random)。
- Certificate:服务器发送其数字证书,其中包含公钥并由证书颁发机构(CA)签名。客户端对该证书进行校验。
- Server Key Exchange(可选):如果所选 cipher suite 需要(例如临时 Diffie-Hellman),服务器会发送密钥交换参数。
- Server Hello Done:服务器表示其初始握手部分已完成。
- Client Key Exchange:客户端生成 pre-master secret,用服务器证书中的公钥加密后发送给服务器。
- Change Cipher Spec(客户端):客户端发送
Change Cipher Spec消息,表明后续所有消息都将使用协商好的密钥和 cipher suite 加密。 - Encrypted Handshake Message(客户端):客户端发送用新建立的对称密钥加密的
Finished消息,用于校验握手完整性。 - Change Cipher Spec(服务器):服务器发送自己的
Change Cipher Spec消息。 - Encrypted Handshake Message(服务器):服务器发送同样经过加密的
Finished消息。 - Application Data:双方现在即可交换加密的应用数据。
代理类型与 TLS 握手的交互
代理会根据自身工作模式改变 TLS 握手的发起与处理方式。
正向代理(不拦截)
正向代理为需要访问外部资源的客户端充当中间人。对于 HTTPS 流量,不拦截的正向代理通常作为 TCP 隧道运行。客户端需显式配置为使用该代理。
机制:
客户端向代理发送 HTTP CONNECT 请求,以建立通往源站服务器的 TCP 隧道。隧道建立后,客户端与源站服务器直接通过该隧道完成 TLS 握手。代理只转发加密字节,不做解密。
TLS 握手流程:
1. 客户端到代理(TCP):客户端与代理建立 TCP 连接。
2. 客户端 CONNECT 请求:客户端向代理发送 HTTP CONNECT 请求,指定源站服务器的主机名和端口(例如 CONNECT example.com:443 HTTP/1.1)。
3. 代理到源站(TCP):代理与指定的源站服务器建立 TCP 连接。
4. 代理返回 200 OK:若与源站服务器连接成功,代理向客户端返回 HTTP/1.1 200 Connection established。
5. 客户端到源站(经隧道的 TLS):客户端收到 200 OK 后,通过已建立的 TCP 隧道直接与源站服务器发起标准 TLS 握手。
6. 代理转发:代理透明转发客户端与源站服务器之间后续的所有加密字节。它既不参与 TLS 握手,也不解密流量。
代码示例:客户端 CONNECT 请求
CONNECT www.example.com:443 HTTP/1.1
Host: www.example.com:443
Proxy-Connection: Keep-Alive
代理响应
HTTP/1.1 200 Connection established
反向代理(TLS 终止)
反向代理位于一台或多台源站服务器之前,拦截客户端发往这些服务器的请求。对于 HTTPS 流量,反向代理通常执行 TLS 终止。
机制:
反向代理接收客户端的 HTTPS 请求,终止 TLS 连接并解密流量,然后与后端源站服务器建立一条新的连接(该连接可以是 TLS 加密的,也可以不是)。
TLS 握手流程:
1. 客户端到反向代理(TLS 握手 1):
* 客户端直接与反向代理完成标准 TLS 握手。
* 反向代理向客户端出示自己的数字证书。
* 客户端与反向代理之间建立安全加密通道。
2. 反向代理解密:反向代理解密客户端的请求。
3. 反向代理到源站(TLS 握手 2 或 HTTP):
* 反向代理随后与相应的后端源站服务器发起一条新的连接。
* 该连接可以是明文 HTTP(在可信内网中常见),也可以是另一条 TLS 加密连接(用于端到端加密)。
* 若使用 TLS,反向代理充当客户端,与出示自身证书的源站服务器完成第二次 TLS 握手。
4. 源站处理:源站服务器处理请求,并将响应返回给反向代理。
5. 反向代理加密:若与客户端的连接是 TLS,反向代理会用面向客户端的 TLS 会话密钥重新加密响应。
6. 反向代理到客户端:加密后的响应被发回客户端。
透明代理(MITM TLS 拦截)
透明代理在客户端未显式配置的情况下拦截流量。对于 HTTPS,这通常采用中间人(MITM)方式。
机制:
当客户端尝试连接 HTTPS 站点时,透明代理会拦截连接。它为目标域名生成一张由自有根 CA 签发的伪造证书。客户端与代理完成 TLS 握手,代理再与源站服务器完成另一次 TLS 握手。这样代理便可解密、检查并可能修改流量。要做到不出现证书错误,客户端必须信任代理的根 CA 证书。该方式在企业安全监控环境中很常见。
代理类型与 TLS 交互对比
| 特性 | 直连 TLS | 正向代理(不拦截) | 反向代理(TLS 终止) | 透明代理(MITM) |
|---|---|---|---|---|
| TLS 握手位置 | 客户端 ↔ 源站服务器 | 客户端 ↔ 源站服务器(经隧道) | 客户端 ↔ 代理;代理 ↔ 源站服务器 | 客户端 ↔ 代理;代理 ↔ 源站服务器 |
| 代理是否解密 | 不适用 | 否 | 是(客户端侧连接) | 是 |
| 代理证书 | 不适用 | 不适用 | 代理自身的证书 | 代理动态生成的证书 |
| 端到端加密 | 是 | 是 | 否(代理可见明文) | 否(代理可见明文) |
| 客户端是否知情 | 直连 | 显式配置 | 不知情(把代理当作源站) | 不知情(透明重定向) |
| 主要使用场景 | 常规网页浏览 | 客户端访问控制、缓存 | 负载均衡、WAF、API gateway | 企业安全、内容过滤 |
安全注意事项
通过代理建立安全连接时,会带来若干安全影响:
- 对代理的信任:
- 正向代理:由于代理只是隧道传输加密数据,就数据机密性而言对信任的要求极低。不过,代理仍可能记录连接元数据(IP、域名)。
- 反向代理 / 透明代理(MITM):这类代理会解密流量。由于它们可以接触到解密后的敏感数据,对代理运营方的信任变得至关重要。对于透明 MITM 代理,客户端必须显式信任代理的根 CA,通常是将其安装到系统信任库中。
- 证书固定(certificate pinning):使用证书固定的应用在经过反向代理或透明 MITM 代理时可能连接失败,因为代理出示的证书与预期的源站服务器证书不同。这是为防范 MITM 攻击而设计的安全特性。
- 强制 TLS 版本与 cipher suite:代理可配置为强制使用特定的 TLS 版本和 cipher suite,即使客户端或源站服务器支持已弃用或较弱的加密协议,也可禁止使用,从而提升安全性。
- 日志与审计:代理(尤其是反向代理和透明代理)可对解密后的流量提供丰富的日志能力,有助于安全审计与事件响应。
- 性能开销:在代理上做 TLS 终止会带来加解密的计算开销,在高流量环境中必须予以考虑。通常采用硬件加速(例如 SSL offloading)来缓解这一问题。
