1. TLS 协议概述:发展历史、应用场景、基本架构
聊到 TLS,我得先坦白一件事。我刚入行那会儿,觉得 SSL 和 TLS 就是给网站加个小锁,装个证书就完事了。直到有一次线上服务频繁出现握手超时,扒开流量一看——客户端只支持 TLS 1.2,服务器却还在用 SSL 3.0,协商失败直接断连。嗯,从那天起我才真正开始啃 TLS 的底层细节。
这一章我们先搭个全景。你弄懂了 TLS 的来龙去脉、用在哪、长什么样,后面的密钥交换和协商细节才有土壤。
1.1 发展历史:从 SSL 到 TLS 1.3
TLS 的前身是 Netscape 公司开发的 SSL(Secure Sockets Layer)。你想想看,90 年代中期,网上购物刚起步,信用卡明文传输——简直是裸奔。于是 SSL 1.0 在 1994 年诞生,但内部测试就发现问题,从未公开发布。真正面世的是 SSL 2.0(1995),不过漏洞一堆,比如不能防止中间人篡改。
我记得当时很多银行还在用 SSL 2.0,安全审计报告里全是高危。于是 1996 年 SSL 3.0 出来,补了大部分设计缺陷,引入了现在还在用的握手流程雏形。我最早接触的就是 SSL 3.0,那时候配置个 Apache 还要改一堆 OpenSSL 参数。
1999 年,IETF 接手并改名为 TLS 1.0(RFC 2246)。说白了就是 SSL 3.0 的微调版本,向后兼容。之后 TLS 1.1(2006)对抗 CBC 攻击做了改进,TLS 1.2(2008)则大改——去掉了很多老旧算法,支持 SHA-256 和 AEAD。
真正让我兴奋的是 TLS 1.3(2018)。握手从两次往返变成一次,移除了所有不安全算法,还强制前向安全。我在生产环境升级 TLS 1.3 时,页面加载时间直接降了 30%。
| 版本 | 发布年份 | 关键改进 | 当前状态 |
|---|---|---|---|
| SSL 2.0 | 1995 | 首次公开发布 | 已禁用(RFC 6176) |
| SSL 3.0 | 1996 | 引入握手流程、密码套件 | 已禁用(POODLE 攻击) |
| TLS 1.0 | 1999 | 标准化,微调 SSL 3.0 | 已弃用 |
| TLS 1.1 | 2006 | 防御 CBC 攻击 | 已弃用 |
| TLS 1.2 | 2008 | AEAD、SHA-256、灵活密钥交换 | 广泛使用 |
| TLS 1.3 | 2018 | 1-RTT 握手、前向安全、移除不安全算法 | 推荐部署 |
1.2 应用场景:不止是 HTTPS
一说到 TLS,大多数人第一反应是浏览器那个小锁。没错,HTTPS 是最广为人知的应用——HTTP over TLS (RFC 2818)。但 TLS 的用武之地远不止 Web。
- 电子邮件:SMTP、IMAP、POP3 都可以加 TLS 保护。我配置过很多邮件服务器,不少人只给端口 25 加 STARTTLS,却忽略提交端口 587 的强制 TLS。
- VPN:OpenVPN 底层就是 TLS 握手,用来交换密钥。
- 即时通讯:Signal、WhatsApp 都用 TLS 保护信令通道。
- IoT 轻量设备:DTLS(Datagram TLS)是基于 UDP 的 TLS 变种,适合传感器和嵌入式设备。
- 微服务内部通信:在 Kubernetes 里,istio 使用 mTLS(双向 TLS)保证服务间身份认证和加密。
1.3 基本架构:协议栈长什么样?
TLS 协议并不是一个大块头。它分为两层:底层是 TLS 记录协议,上层是几个子协议。我画张图帮你理清结构。
从上往下看:记录协议是整个 TLS 的传输载体。它把上层数据(握手消息、警报、应用数据)分片、可选压缩、添加消息认证码(MAC),再加密后交给 TCP。我在排查 TLS 性能瓶颈时,经常抓包分析记录层的长度字段——有时候 MTU 问题会导致大量碎片。
三个子协议跑在记录协议之上:
- 握手协议:负责协商加密套件、密钥交换、证书验证。这是密钥安全性的核心,后面我们会花好几章细讲。
- 变更密码规范协议:一个简单信号,告诉对端“我要开始用刚才协商好的密钥加密了”。只有 1 个字节。
- 警报协议:发送错误或关闭通知,比如证书过期、解密失败。我见过很多业务日志里出现 “bad_record_mac” 警报,通常是网络中间件修改了密文。
openssl s_client -tls1_2 -connect host:port 看握手过程。如果遇到 SSL alert number 40 (handshake failure),多半是密码套件不匹配或证书有问题。
1.4 基本安全目标与协商流程
TLS 要干四件事:身份认证、机密性、完整性、前向安全性。具体通过握手协商达成:
- 客户端发送 ClientHello(支持的 TLS 版本、密码套件、随机数)。
- 服务端回复 ServerHello(选定版本、套件、随机数),并发送证书(可选)。
- 密钥交换:比如 Diffie-Hellman 或 RSA,双方算出预主密钥。
- 双方派生主密钥和会话密钥,然后发送 ChangeCipherSpec,开始加密通信。
你想想看,整个流程设计得非常精巧——既要防重放,又要防降级攻击。我曾在代码审计中发现有人硬编码了 TLS_RSA_WITH_AES_128_CBC_SHA,这种套件没有前向安全,一旦私钥泄露,所有历史流量都能解密。所以我个人建议,现在新项目一律优先选择 TLS 1.3 或 TLS 1.2 的 ECDHE 套件。