2、SSL/TLS 基本工作原理
要说清楚 SSL/TLS,我们得先聊聊它到底解决了什么问题。我早年调一个 HTTPS 接口时,数据抓包一看全是明文,瞬间冷汗就下来了——要是中间有人偷听,密码、 全白送。所以,SSL/TLS 本质上就是给通信上了三把锁:加密(别人看不懂)、身份校验(确保对方是真的)、完整性校验(数据没被改过)。
2.1 两层协议:握手层和记录层
SSL/TLS 并不是一个单一的协议,而是分上下两层。每次连接都得先走握手,然后才能安全地传数据。我个人习惯把这两层理解为「建房子」:握手协议是打地基和搭框架,记录协议是往房间里放家具。
- 握手协议(Handshake Protocol)——负责协商密码套件、交换密钥、验证证书。这一层决定了你们用什么加密、用什么 hash。
- 记录协议(Record Protocol)——负责把应用层数据分段、压缩(TLS 1.3 取消了)、加 MAC、加密,然后丢给 TCP 层。
2.2 握手流程:一句“你好”来回四次
拿最经典的 TLS 1.2 完整握手来说,不算恢复会话,大概需要 2 个 RTT(往返延迟)。我曾在生产环境遇到过因为握手延迟太长导致 App 超时,后来切了 TLS 1.3 的 0-RTT 才好。下面这张图能帮你快速理清流程:
2.3 记录协议到底做了什么?
握手完成后,记录协议就上场了。每次发数据时,它会先把应用层数据切成合适大小的片段(默认最大 16KB),然后可选地压缩(TLS 1.3 移除了这一步),接着加上消息认证码(MAC),最后用协商好的对称密钥加密。我举个例子帮你理解:
原始数据: "Hello, 这是支付请求"
→ 分段: ["Hello, 这是", "支付请求"]
→ 加 MAC: [片段1 || MAC1, 片段2 || MAC2]
→ 加密: [AES-GCM加密(片段1 || MAC1), AES-GCM加密(片段2 || MAC2)]
→ 添加记录头 (5字节): [内容类型(1B) || 版本(2B) || 长度(2B)]
→ 发送
2.4 密码套件的“三要素”
密码套件是握手协议的核心产物。说白了,就是双方共同拍板的一个套餐——密钥交换算法 + 身份认证算法 + 对称加密 + MAC/认证加密。下面这张表是常见的几个例子:
| 密码套件 | 密钥交换 | 认证 | 对称加密 & MAC |
|---|---|---|---|
| TLS_RSA_WITH_AES_128_CBC_SHA | RSA | RSA 证书 | AES-128-CBC + SHA-1 HMAC |
| TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 | ECDHE | RSA 证书 | AES-128-GCM (AEAD) |
| TLS_AES_128_GCM_SHA256 (TLS 1.3) | (由密钥协商隐式完成) | 任意证书 | AES-128-GCM + HKDF |
我个人建议:新项目直接使用 TLS 1.3,因为它把密码套件精简到了 5 个,而且把「密钥协商 + 认证 + 加密」全部设计成了强安全组合,几乎没有配置错误的空间。
2.5 避坑:证书链和信任锚
你可能会觉得证书验证是 CA 的事,跟你没关系。我以前也是这么想的,直到自己搭内部 CA 时,忘了把中间证书配置到服务端,结果移动端一直报错“无法建立安全连接”。检查之后才发现:服务端必须发送完整的证书链(不包括根,因为客户端信任的只有根),否则客户端没法拼出信任路径。
- 服务端:在 ServerHello 后发 Certificate 消息,带上自己的证书 + 中间 CA 证书(可多个)。
- 客户端:用本地信任的根 CA 去校验证书链,检查有效期、颁发者、扩展(如 SAN)。
- 证书吊销检查:可配 OCSP Stapling 或 CRL,但很多默认不启用——我建议至少开 OCSP Stapling 以减少客户端延迟。