为什么需要 TLS?
HTTP 协议默认是明文传输的。这意味着数据在网络上传输时,不仅内容可以被轻易窃听,还可能被中间人篡改。
为了保证安全,我们需要加密通信。
如果双方直接约定一个密钥(对称加密),这个密钥在传输给对方的过程中一旦被截获,加密就失效了。
如果使用公钥/私钥(非对称加密),虽然解决了密钥传输的问题,但存在中间人攻击(MITM)的风险——攻击者可以拦截请求,向客户端伪装成服务器,向服务器伪装成客户端。
所以需要引入 CA (Certificate Authority)。服务器将公钥交给 CA 签名生成证书,客户端通过验证证书来确保服务器身份的真实性。
TLS (Transport Layer Security) 的核心目标只有两个:
- 身份认证:验证通信对方(通常是服务器)的身份。
- 密钥协商:安全地交换出一个对称密钥(Session Key),用于后续高效的数据加密传输。
TLS 1.2 的握手流程
在 TLS 1.3 普及之前,互联网主要通过 TLS 1.2 协议保障安全。它的握手过程需要两个往返(2-RTT),相对繁琐。
假设客户端要连接服务器:
- Client Hello: 客户端发送支持的 TLS 版本、加密套件列表(Cipher Suites)和一个随机数 A。
- Server Hello: 服务器从中选择一个加密套件,生成随机数 B,并发回自己的证书。
- Key Exchange: 服务器计算并发送密钥协商需要的参数(Server Params),并请求客户端确认。
- Client Key Exchange: 客户端验证证书有效性后,根据参数生成客户端的参数(Client Params)发给服务器。
- Change Cipher Spec: 双方利用随机数 A、B 和交换的 Params 算出最终的 Session Key。客户端通知服务器“之后的通信开始加密”。
- Finished: 客户端发送一条用 Session Key 加密的消息,服务器验证并回复一条加密消息,握手结束。
TLS 1.2 的一个主要历史包袱是支持 RSA 密钥交换。这种方式不具备前向安全性 (Forward Secrecy)——如果服务器的私钥在未来泄露,攻击者可以用它解密所有历史截获的流量。
TLS 1.3 的改进
2018 年发布的 TLS 1.3 做了大幅简化和安全性升级。
它废弃了 RSA 密钥交换等不支持前向安全的算法,强制使用 Diffie-Hellman (ECDHE) 进行密钥协商。 因为算法选择变少且标准化,客户端不需要等服务器“选好”算法,可以在发送 Hello 时直接把自己的公钥参数算好发过去。
这样握手被压缩到了 1-RTT:
- Client Hello: 客户端发送支持的算法、随机数 A,并直接附带自己的公钥参数(Key Share)。
- Server Hello + Finished: 服务器收到后,直接计算出 Session Key,发回服务器公钥参数、证书和加密的 Finished 消息。
0-RTT 对于近期连接过的服务器,TLS 1.3 允许客户端利用之前的缓存凭证,在发送 Client Hello 的同时直接发送加密的 HTTP 请求(如 GET /)。这大大降低了延迟,但也带来了重放攻击的风险,通常只对幂等操作开放。
mTLS (Mutual TLS) 与微服务
在浏览器访问网站的场景中,通常是 单向认证:客户端验证服务器证书,服务器不验证客户端(因为互联网对所有人开放)。
但在微服务架构中,服务间的调用需要严格的权限控制。比如 Payment Service 不应接受任意请求,只应接受来自 Order Service 的请求。
这就需要 mTLS(双向认证)。 在握手阶段,服务器不仅出示证书,还会要求客户端也出示证书。 服务器会验证:
- 客户端证书是否由可信的内网 CA 签发。
- 客户端证书中的身份标识(如 SAN 里的 SPIFFE ID)是否在允许访问列表中。
在 Kubernetes 的 Service Mesh(如 Istio)中,通常由 Sidecar (Envoy) 代理自动处理这些逻辑。应用代码可以像往常一样发起 HTTP 请求,Sidecar 会在网络层拦截流量,自动进行 mTLS 握手和加密传输,从而实现了零信任 (Zero Trust) 架构。
总结
- TLS 1.2: 需要 2-RTT 握手,部分旧算法不支持前向安全。
- TLS 1.3: 简化为 1-RTT,支持 0-RTT,强制前向安全,更快更安全。
- mTLS: 用于微服务间的双向身份验证,是零信任网络的基础。