1. TLS 握手基础:从协议概览到密码套件协商
各位同学好,我是老周。今天咱们正式进入《TLS会话恢复机制与性能调优》的第一章。说实话,TLS握手是整个安全通信的基石,你后面要理解会话恢复、0-RTT这些高级特性,都得先把握手吃透。这一章我会带着大家把TLS协议的全貌、1.2和1.3的握手流程、密码套件协商这些基础过一遍。
1.1 TLS协议概述
TLS,全称Transport Layer Security,中文叫传输层安全协议。它的前身是SSL,现在大家基本都用TLS这个叫法了。TLS工作在传输层之上、应用层之下,说白了就是在TCP上面加了一层安全壳。
这个协议主要干三件事:
- 身份认证——确认你连接的服务端是真的,不是冒牌货
- 密钥协商——双方安全地商量出一个对称密钥
- 数据加密——用商量好的密钥加密后续通信内容
我个人习惯把TLS比作一个「安全握手协议」。你想想看,两个人见面先握手确认身份,然后悄悄约定一个暗号,之后就用暗号加密交流。TLS本质上就是这个逻辑。
核心要点:TLS不负责传输数据,它只负责让传输变得安全。真正的数据传输还是交给TCP去做。
1.2 TLS 1.2 完整握手流程
TLS 1.2是目前生产环境中使用最广泛的版本。虽然1.3已经出来好几年了,但很多老系统还在跑1.2。我在项目中遇到过不少客户,升级到1.3时因为兼容性问题回退到1.2,所以这个版本你必须掌握。
完整的TLS 1.2握手需要2-RTT(两次往返),流程如下:
- ClientHello:客户端发消息,告诉服务端自己支持的TLS版本、密码套件列表、随机数等
- ServerHello:服务端从客户端列表里选一个密码套件,发回自己的随机数
- Certificate:服务端发送自己的数字证书(含公钥)
- ServerKeyExchange:如果需要,服务端发送密钥交换参数(比如DH参数)
- ServerHelloDone:服务端说「我发完了」
- ClientKeyExchange:客户端发送密钥交换参数(比如DH公钥)
- ChangeCipherSpec:客户端说「我要开始加密了」
- Finished:客户端发送加密后的握手摘要,用于完整性校验
- ChangeCipherSpec:服务端也说「我要开始加密了」
- Finished:服务端发送加密后的握手摘要
嗯,这里要注意,TLS 1.2的握手消息是明文传输的,只有ChangeCipherSpec之后的消息才加密。这就意味着,如果中间人想搞破坏,在握手阶段就能看到你协商了啥。
避坑指南:我曾经帮一个客户排查性能问题,发现每次连接都要做完整握手,延迟高达200ms。后来一看,原来是服务端没开会话缓存。TLS 1.2的完整握手确实慢,2-RTT在跨洋链路上就是实打实的延迟。
1.3 TLS 1.3 握手改进
TLS 1.3是2018年发布的,它最大的改进就是——把握手从2-RTT砍到了1-RTT。怎么做到的?说白了就是「合并消息」和「精简流程」。
我们来看看TLS 1.3的握手流程:
- ClientHello:客户端直接带上自己的密钥交换参数(比如DH公钥)和猜测的密码套件
- ServerHello + 证书 + 服务端参数 + Finished:服务端一次性回复所有内容
- 客户端Finished:客户端确认握手完成
你看,TLS 1.3把服务端的多个消息合并成了一个Flight。而且,它去掉了ChangeCipherSpec这个冗余消息,也砍掉了那些不安全的密码套件。
为什么会这样?因为TLS 1.3的设计者发现,1.2的很多步骤其实可以并行处理。比如证书和密钥交换参数,没必要分开发送。
| 对比项 | TLS 1.2 | TLS 1.3 |
|---|---|---|
| 握手RTT | 2-RTT | 1-RTT |
| 支持的密码套件 | 37种(含不安全) | 5种(仅安全) |
| ChangeCipherSpec | 需要 | 移除 |
| 会话恢复 | Session ID / Session Ticket | PSK + 0-RTT |
| 前向安全性 | 可选 | 强制 |
个人经验:我建议新项目直接上TLS 1.3。虽然1.2还能用,但1.3在性能和安全性上都更优。唯一要注意的是,有些老旧的客户端(比如Android 4.x)不支持1.3,这时候需要做版本协商降级。
1.4 密码套件协商
密码套件,英文叫Cipher Suite,它是一组算法的组合。TLS握手时,客户端和服务端要商量好用哪一套算法来干活。
一个典型的TLS 1.2密码套件长这样:
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
拆开来看:
- TLS:协议前缀
- ECDHE:密钥交换算法(椭圆曲线Diffie-Hellman临时密钥)
- RSA:身份认证算法
- AES_256_GCM:对称加密算法(AES-256,GCM模式)
- SHA384:消息认证码算法(HMAC-SHA384)
到了TLS 1.3,密码套件简化了很多,只保留5个:
TLS_AES_128_GCM_SHA256
TLS_AES_256_GCM_SHA384
TLS_CHACHA20_POLY1305_SHA256
TLS_AES_128_CCM_SHA256
TLS_AES_128_CCM_8_SHA256
你看,TLS 1.3的密码套件不再包含密钥交换和身份认证算法,因为这两部分被独立出来了。这样设计的好处是,密码套件只负责加密和完整性,密钥交换和认证由握手协议单独处理。
协商过程其实很简单:客户端在ClientHello里列出自己支持的所有密码套件(按优先级排序),服务端从里面选一个自己也能支持的。如果服务端一个都选不出来,那就握手失败。
避坑指南:我曾经遇到过一个问题,客户端和服务端都支持TLS 1.2,但握手就是失败。查了半天,发现客户端只支持ECDHE密钥交换,而服务端证书是RSA的,但服务端没配ECDSA证书。说白了,密码套件里的每个组件都得匹配上,缺一个都不行。
本章知识体系
下面这张图展示了本章的核心知识结构,我把它画成了SVG,方便大家对照理解:
这张图把本章的四个核心模块串起来了。从TLS协议概述出发,分别展开TLS 1.2和1.3的握手流程,最后落到密码套件协商。大家可以看到,TLS 1.3在延迟和安全性上都有明显优势,但密码套件的选择范围也大幅缩小了。
好了,第一章的内容就到这里。记住,握手是TLS性能的起点,后面讲会话恢复和0-RTT时,你会反复用到今天学的这些知识。