1. TLS 协议基础:从 SSL 到 TLS 的演进之路

聊 TLS 终止技术之前,咱们得先把地基打牢。TLS 协议本身,说白了就是给网络通信加了一把「加密锁」。我在做安全架构评审时,发现很多团队把 TLS 和 SSL 混着叫,其实这里头有段历史。

1.1 TLS 发展历史:一场被迫的升级

TLS 的前身是 SSL,全称 Secure Sockets Layer。网景公司在 1994 年搞出了 SSL 1.0,但压根没公开发布——因为漏洞太多,内部就毙掉了。真正面世的是 1995 年的 SSL 2.0,不过那玩意儿现在看简直是筛子。

我记得 2014 年有个客户还在用 SSL 3.0,我劝他升级,他说「跑得好好的换它干嘛」。结果没过几个月,POODLE 攻击爆出来,SSL 3.0 彻底凉了。嗯,这就是不升级的代价。

版本 发布年份 状态 关键问题
SSL 1.0 1994 未公开发布 内部发现严重安全缺陷
SSL 2.0 1995 已废弃(2011) 无证书链验证、MAC 弱
SSL 3.0 1996 已废弃(2015) POODLE 攻击、RC4 弱
TLS 1.0 1999 已废弃(2021) BEAST 攻击、CBC 模式问题
TLS 1.1 2006 已废弃(2021) 改进 CBC、增加 IV
TLS 1.2 2008 广泛使用 AEAD 支持、GCM 引入
TLS 1.3 2018 推荐使用 1-RTT、前向安全、移除不安全算法

核心结论:现在生产环境最低也得 TLS 1.2,能用 TLS 1.3 就别犹豫。SSL 全系列已经进坟墓了,别挖出来用。

1.2 TLS 与 SSL 的关系:父子还是兄弟?

很多人以为 TLS 是 SSL 的改名版,其实不完全是。1999 年 IETF 接手了 SSL 标准化工作,觉得「SSL」这名字被网景注册了,干脆改叫 Transport Layer Security。但底层设计基本继承自 SSL 3.0。

你想想看,TLS 1.0 和 SSL 3.0 的差异其实很小,小到很多实现里 TLS 1.0 就是 SSL 3.1。但到了 TLS 1.3,改动就大了——握手从 2-RTT 砍到 1-RTT,还砍掉了一堆不安全算法。

我的建议:写代码或配服务器时,别在配置里写 SSL 了。Nginx 里配 ssl_protocols 只是历史遗留命名,实际走的是 TLS。统一叫 TLS,显得专业。

1.3 TLS 握手协议概述:一次加密的「对暗号」

TLS 握手,说白了就是客户端和服务器互相确认身份、商量加密方式的过程。我在调一个跨国电商的 HTTPS 性能时,发现握手占了连接建立时间的 70%。优化握手,就是优化用户体验。

咱们先看 TLS 1.2 的完整握手流程,这是最经典的版本:

  1. ClientHello:客户端发个招呼,带上支持的 TLS 版本、密码套件列表、随机数。
  2. ServerHello:服务器从列表里挑一个密码套件,发回自己的随机数和证书。
  3. Certificate:服务器把证书链发给客户端,客户端验证合法性。
  4. ServerKeyExchange:如果是 DHE/ECDHE 密钥交换,服务器发临时公钥。
  5. ServerHelloDone:服务器说「我发完了」。
  6. ClientKeyExchange:客户端生成预主密钥,用服务器公钥加密后发过去。
  7. ChangeCipherSpec:双方切换加密模式。
  8. Finished:双方发一条加密的验证消息,确认握手成功。

注意:ChangeCipherSpec 在 TLS 1.3 里被移除了。如果你还在用 TLS 1.2,记得检查服务器是否支持 Session Resumption,能省一次完整握手。

TLS 1.3 的握手就简洁多了,只需要 1-RTT:

  • 客户端直接发 ClientHello + 密钥共享参数
  • 服务器回复 ServerHello + 证书 + 完成消息
  • 双方立刻就能发加密数据

我曾经帮一个视频直播平台做优化,从 TLS 1.2 切到 1.3,首屏加载时间降了 35%。说白了,少一次往返就是快。

TLS 1.2 完整握手流程 客户端 服务器 ① ClientHello ② ServerHello + Certificate ③ ServerKeyExchange ④ ServerHelloDone ⑤ ClientKeyExchange ⑥ ChangeCipherSpec ⑦ Finished(双向) 加密数据 加密数据 ⑧ 加密通信开始

1.4 TLS 记录协议概述:数据怎么打包上路?

握手完了,数据怎么传?这就轮到记录协议上场了。它负责把应用层数据切成小块,压缩(可选)、加 MAC、加密,然后扔给 TCP 发出去。

记录协议的结构其实很简单,就 5 个字段:

字段 长度 说明
Content Type 1 字节 标识记录类型(20=ChangeCipherSpec, 21=Alert, 22=Handshake, 23=Application Data)
Protocol Version 2 字节 TLS 版本号,如 0x0303 表示 TLS 1.2
Length 2 字节 负载长度,最大 2^14 字节(16384)
Payload 可变 实际数据,可能包含 MAC 和填充
MAC(可选) 可变 消息认证码,TLS 1.3 中由 AEAD 替代

你可能会问:「为什么最大只有 16KB?」其实这是 TCP 的 MTU 限制决定的。我见过有人把记录设得太大,结果 IP 分片导致性能暴跌。嗯,这里要注意:记录大小最好控制在 1400 字节以内,避免分片。

实战技巧:抓包时看到 TLS 记录长度超过 16384,那一定是实现有 bug。我曾经排查过一个性能问题,发现某开源库把记录长度写成了 65535,结果接收端直接崩了。

记录协议在 TLS 1.3 里做了简化:

  • 移除了压缩功能(压缩 + 加密 = CRIME/BREACH 攻击的温床)
  • MAC 和加密合并为 AEAD(Authenticated Encryption with Associated Data)
  • Content Type 被加密,中间人看不到你传的是握手消息还是应用数据

说白了,TLS 1.3 的记录协议更安全、更简洁。我建议新项目直接上 TLS 1.3,别在 1.2 上纠结了。