同一个接口,HTTP 调只要 50ms,换成 HTTPS 慢慢悠悠要 200ms——多出来的 150ms 花哪了?不全是加密的锅,大头在握手:HTTPS 比 HTTP 多了一层 TLS 握手,光建连接就要多花一两个来回。

这一篇就讲这多出来的来回——TLS 握手在干什么,以及为什么 TLS 1.3 能把它从 2 个 RTT 砍到 1 个。

HTTPS = HTTP over TLS

先把 HTTPS 的结构理清楚。HTTP 是明文传输,任何人截获就能看懂。HTTPS 不是「另一种 HTTP」,而是「HTTP 跑在 TLS 加密通道里」:

应用层:    HTTP(明文报文)
传输安全层:  TLS(加密、认证、完整性)
传输层:     TCP(可靠传输)

TLS 在 HTTP 和 TCP 之间插了一层,做三件事:加密(别人截获看不懂)、认证(确认对方身份)、完整性(数据没被篡改)。这三件事都不是白做的,每一件都需要握手来协商和建立。

TLS 握手的三件事

握手要在第一次传数据前完成三件事:

  1. 协商加密套件:双方商量用哪种加密算法(对称加密用什么、密钥交换用什么)。这个在 ClientHello 和 ServerHello 里完成。
  2. 交换密钥:对称加密需要一个只有双方知道的「会话密钥」。这个密钥不能明文传,要用密钥交换算法(ECDHE)安全地协商出来。
  3. 验证身份:客户端验证服务器的证书(下一篇详讲),确认「你真的是 rubyfun.cn,不是中间人」。

TLS 1.2 握手时序:ClientHello 到 Finished

跟着 TLS 1.2 的时序走一遍:

  • ClientHello:客户端发出支持的 TLS 版本、加密套件列表、一个随机数。
  • ServerHello + Certificate + ServerKeyExchange + ServerHelloDone:服务器选定套件、返回证书、发出密钥交换参数。
  • ClientKeyExchange + ChangeCipherSpec + Finished:客户端发密钥交换参数,通知「接下来加密」,发加密验证。
  • ChangeCipherSpec + Finished:服务器也通知加密,发验证。

注意这是 2 个 RTT:第一个 RTT 是 ClientHello → ServerHello,第二个 RTT 是密钥交换和 Finished 验证。要等第二个 Finished 确认,才能开始发应用数据(HTTP)。

TLS 1.3:怎么减到 1 个 RTT

TLS 1.2 的 2 个 RTT 是性能负担。TLS 1.3(RFC 8446)把它砍到 1 个 RTT,关键改动是密钥交换算法

TLS 1.3 握手时序:1 RTT

TLS 1.3 怎么省掉一个 RTT?它把密钥交换参数提前了:

  • TLS 1.2 里,客户端要等服务器发完证书,才能算出密钥,再发自己的密钥参数。这是两步。
  • TLS 1.3 里,客户端在 ClientHello 时就带上密钥交换参数(假设用 ECDHE)。不等服务器回应,客户端已经在算密钥了。服务器收到 ClientHello,一次回完所有东西(证书、密钥参数、Finished),客户端收到就能发应用数据。

这个改动的前提是 TLS 1.3 砍掉了一些不安全的算法,只保留 ECDHE 这种支持「前向安全」的密钥交换。前向安全的意思是:即使服务器私钥以后泄露,以前录下的流量也无法被解密——因为每次会话的密钥是临时协商的,私钥只是用来验证身份,不直接参与加密。

TLS 1.3 还支持 0-RTT 恢复:如果客户端之前连过这个服务器(有缓存的会话票据),它可以在第一个包里就带上应用数据,连握手那个 RTT 都省了。代价是 0-RTT 数据有重放风险(攻击者截获重发),所以只能用于幂等请求(GET),不能用于会改变状态的请求(POST 转账)。

HTTPS 的总开销

把 TCP 握手、TLS 握手、HTTP 请求叠起来,HTTPS 比 HTTP 多出来的开销就清楚了:

HTTPS 完整开销构成

  • HTTP(明文):TCP 握手 1 RTT + HTTP 请求 1 RTT = 2 RTT
  • HTTPS + TLS 1.2:TCP 1 + TLS 2 + HTTP 1 = 4 RTT
  • HTTPS + TLS 1.3:TCP 1 + TLS 1 + HTTP 1 = 3 RTT
  • HTTPS + TLS 1.3 + 0-RTT:TCP 1 + 0 + HTTP 1 = 2 RTT(和明文 HTTP 一样)

所以 HTTPS 不是「免费的」,建连接的延迟确实更高。但现代优化(TLS 1.3、会话恢复、连接复用)已经把这个差距压到很小。加上 keep-alive 复用连接,握手开销被摊薄到几乎可以忽略。

取舍与边界

TLS 这层有几个值得注意的点:

  • 加密的计算开销现在很小。早期 HTTPS 慢一部分是 CPU 算力不够,现在 AES-NI 硬件指令让对称加密几乎零开销,瓶颈在 RTT 不在 CPU。
  • 证书验证是握手里可能拖慢的一环。客户端要验证证书链(下一篇讲),可能涉及在线查吊销状态(OCSP),这个网络查询可能拖慢握手。OCSP Stapling 让服务器替客户端查好 stap 在响应里,避免客户端额外查询。
  • TLS 1.3 砍算法换来性能。它删掉了 RSA 密钥交换、静态 DH 等不安全算法,只留 ECDHE。这既是安全升级,也是性能优化——少一个 RTT。

收束:HTTPS 的延迟代价在握手,不在加密本身

TLS 握手是 HTTPS 比 HTTP 多出来的开销,核心是那 1~2 个 RTT。TLS 1.3 把它减到 1 个,会话恢复甚至能做到 0-RTT。理解了握手开销,你才会明白为什么连接复用(keep-alive)对 HTTPS 尤其重要——每次新建连接都要重新握 TLS,这个成本比明文 HTTP 高得多。

下一篇讲握手里最关键的一环:证书与信任链。TLS 加密保证了「别人看不懂」,但怎么确认「对面真的是 rubyfun.cn」?这就靠证书和 CA 体系。


关于十三Tech

我是十三,All in AI Agent 方向的架构师,专注 AI 工程实践。

我相信 AI 是程序员的最佳搭档,也希望帮助每一位开发者更好地驾驭 AI。

如果你想继续跟完这套「图解 HTTP」,欢迎关注公众号 「十三Tech」。后续会按 URL 与报文、连接与传输、缓存与协商、安全与边界、HTTP/2 与 HTTP/3 这条线更新。

十三Tech公众号二维码