TLS 握手流程简介

聊TLS握手之前,我先讲个真实的事。几年前我排查一个支付接口的故障,发现客户端和服务端互相不信任,日志里全是握手失败的记录。折腾了一上午,最后发现是TLS版本不匹配——客户端坚持用TLS 1.0,服务端只接受1.2以上。你说冤不冤?

所以,搞懂TLS握手的基本流程,是审计日志工作的第一步。说白了,握手就是通信双方在正式传数据之前,先互相打招呼、亮证件、商量加密规则的过程。

握手的核心目标

TLS握手要解决三个问题:

  • 身份认证:确认对方是不是它声称的那个人
  • 密钥协商:在不安全的信道上安全地商量出一个对称密钥
  • 参数同步:双方确认用哪个TLS版本、哪套密码套件

你想想看,这三个目标任何一个出问题,后面的通信都没法谈。我在项目中见过不少因为证书过期导致握手失败的案例,看起来很基础,但真遇到了还是很头疼。

一次典型的TLS 1.2完整握手

我记得刚入行那会儿,老工程师跟我说:“看TLS握手,就看四个包。”

确实,TLS 1.2的完整握手,核心就四个消息交换:

  1. ClientHello:客户端发起握手,告诉服务端它能支持的TLS版本、密码套件列表,还会生成一个随机数
  2. ServerHello:服务端从客户端列表里挑一个版本和密码套件,也生成一个随机数返回
  3. Certificate:服务端把自己的证书发给客户端,证明身份
  4. ServerHelloDone:服务端说“我这边消息发完了”

客户端收到服务端的证书后,会做两件事:验证证书合法性,然后用服务端公钥加密一个预主密钥(Pre-Master Secret)发回去。

服务端收到后用私钥解密,这样双方都有客户端随机数、服务端随机数、预主密钥——三个东西一起算出主密钥。

关键点:审计日志里最值得关注的,就是ClientHello里带的密码套件列表和ServerHello里最终选定的密码套件。这两个参数直接决定了通信的加密强度。

TLS 1.3的优化

TLS 1.3出来后,握手的流程做了大改。我最喜欢它的一点——去掉了那些不必要的往返。

对比项 TLS 1.2 TLS 1.3
握手耗时 2个RTT(往返时间) 1个RTT(首次),0-RTT(复用)
证书 单独发送 加密后发送
密钥交换 RSA或DH系列 仅支持ECDHE/DHE
ChangeCipherSpec 单独消息 不再需要

你可能会问,为什么TLS 1.3这么快?说白了就是把密钥交换的参数提前放到了ClientHello里。服务端收到后直接算出主密钥,不用等客户端来回折腾。我测试过一个WebRTC场景,从TLS 1.2升级到1.3,握手延迟从80ms降到了40ms左右。

审计提示:1.3的握手参数记录更少,但更关键。因为密码套件只有固定的几个,所以审计时重点关注是否启用了0-RTT——0-RTT虽然快,但有重放攻击风险。

握手中的关键参数记录点

做审计日志时,我建议对每个握手阶段记录以下参数:

  • ClientHello阶段:TLS版本(如0x0303表示TLS 1.2)、密码套件列表、扩展字段
  • ServerHello阶段:实际选用的密码套件、服务器随机数
  • 证书阶段:证书链长度、证书公钥算法(RSA、ECDSA等)、证书有效期
  • 密钥交换阶段:使用的密钥交换算法、临时公钥的曲线参数
  • 握手完成阶段:是否使用了会话复用、是否启用了安全重协商

踩坑提醒:我曾经排查过一个TLS握手失败,日志里只记录了“handshake failure”,没有任何细节。后来才发现是服务端要求客户端证书,但客户端没发。所以审计日志至少要记录“哪一步失败、原因是什么”,否则排查起来太痛苦。

一张图看懂TLS握手流程

下面这张图是我自己整理的,涵盖了TLS 1.2和1.3的典型握手流程。你看一眼就能明白整个骨架。

TLS握手流程图(TLS 1.2 vs 1.3) 客户端 服务端 ClientHello ServerHello Certificate ServerHelloDone ClientKeyExchange 完成(TLS 1.3) TLS 1.2: 2个RTT 需要ChangeCipherSpec 证书明文传输 TLS 1.3: 1个RTT 密钥协商前置+0-RTT 证书加密传输

从审计视角看握手参数

我做审计日志方案时,特别在意下面这几个参数:

  • 密码套件:是否包含弱算法(比如RC4、CBC模式、NULL加密)
  • 证书链:是否为自签名证书、是否过期、是否被吊销
  • 密钥交换算法:是否使用RSA密钥传输(RSA没有前向安全性)
  • 扩展字段:比如SNI(Server Name Indication)是否缺失、ALPN协商结果

我曾经遇到过一个坑——某内部系统直接用TLS 1.0,密码套件是TLS_RSA_WITH_RC4_128_SHA。这在2018年就被认为不安全了。审计日志里如果你只记了“握手成功”,那这个隐患永远发现不了。所以,握手参数的完整性记录,比握手成功与否重要得多。

嗯,这一章的核心就是三句话:握手是双方协商加密参数的过程;TLS 1.2和1.3流程差别很大;审计日志的关键是记录协商结果,而不是只记成功失败。