本节摘要:TLS 是全球部署规模最大的密码协议,它的每个版本号都是一份事故清单的回应:BEAST 与 POODLE 处死了 CBC,Lucky13 处死了 MAC 后加密,DROWN 处死了版本混搭,Heartbleed 教会世界"实现也是攻击面"。2018 年定稿的 TLS 1.3 用一轮握手、只留 AEAD 与临时密钥协商,把本书的工程铁律写进了协议本体。
先看清这台机器的完整运转。以 TLS 1.3 为例,一次握手在两个来回内完成四件事:
注意分工的精确性:ECDHE 负责协商与前向安全(4.3 节),签名与证书负责认证(4.5、6.2 节),HKDF 负责把一个种子密钥展开成多把用途密钥(5.1 节),AEAD 负责机密性与完整性合一(3.3、3.5 节)。一次握手,前五章同台。

TLS 的演化史几乎可以按"攻击驱动的减法"来读,这份清单值得整段记住,因为它是密码工程最贵的一套学费:
工程侧的应对已经有标准动作:只启用 TLS 1.2 与 1.3(1.0/1.1 已于 2021 年被 IETF 正式废弃)、套件白名单只留 AEAD、证书链与 OCSP 装订配齐、用现成库且跟进安全版本。下面的代码是 Python 服务端禁用旧版本的典型姿势:
import ssl ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) # 由库协商最优版本 ctx.minimum_version = ssl.TLSVersion.TLSv1_2 # 禁掉 TLS 1.0/1.1 ctx.options |= ssl.OP_NO_COMPRESSION # 压缩曾致 CRIME 攻击,直接关 # 证书与私钥挂载后即可 serve;套件选择交给库的默认白名单(仅 AEAD) print(ctx.minimum_version, ctx.maximum_version) # 确认边界生效
⚠️ 常见坑:以为"上了 HTTPS 就安全了"。TLS 只保护传输中的数据,两端存储与日志的泄露、0-RTT 重放、降级配置错误都不在它的管辖范围。协议是防线的一段,不是全部。
一,系统时钟偏差——证书"未生效"最常见的原因,虚拟机休眠恢复后尤其多发;二,服务器漏发中间证书,信任链在根与叶之间断掉;三,客户端过旧,不支持服务器仅存的 AEAD 套件;四,服务器配置过严,把合法的旧客户端整体拒之门外;五,防火墙或安全软件在本地拦截并重签证书,浏览器报"颁发机构无效";六,域名与证书的 SAN 不匹配,多见于测试环境借用生产证书;七,协议版本被某一侧硬性禁用,两端没有交集。
排查工具:openssl 的 s_client 子命令能拉出完整握手过程与证书链,浏览器的安全面板能显示协商到的版本与套件,二者对照即可把七种原因收敛成一两种。运维纪律同样重要:证书到期监控、禁用清单随版本更新、变更前在灰度环境跑一遍握手回归——TLS 事故多在变更窗口爆发,而不是在攻击里。
问:老设备实在不支持新协议,允许"协商不上就退回旧版本"不行吗?这正是 POODLE 与 DROWN 教训的来源:降级通道一旦存在,攻击者可以主动制造协商失败,把双方硬推回弱版本。正确的兼容姿势是维护两套并行端点或升级客户端,而不是在单一握手里留回退路径。版本协商的完整性由 Finished 消息的抄本哈希兜底,任何中途篡改协商结果的尝试都会在最后一步校验中现形——这条设计在 1.3 中被贯彻得最彻底。
协议解决了"两台机器如何互信通信",但"服务器公钥凭什么可信"还悬着。下一节拆证书与信任链——公钥的身份证体系。