HTTPS 与 TLS 握手详解

从非对称协商到对称加密,从证书链验证到重放攻击防御,彻底理解 HTTPS 的安全机制

HTTPS / HTTP over TLS TLS 握手 证书链验证 对称密钥协商 重放攻击防御 HMAC / MAC

目录导航(点击跳转)

一、HTTPS 是什么:定义与本质

1 全称与定义

HTTPS 的全称是 HTTP Secure,也常被称为 HTTP over SSLHTTP over TLS。它的核心定义非常简单:

在 HTTP 协议之下增加一个安全层(TLS),用于保障 HTTP 报文的加密传输。HTTPS 本身不改变 HTTP 的语义——URL、Header、Body 该怎么写还怎么写,只是在传输前由 TLS 加密,收到后由 TLS 解密。
2 HTTPS 在协议栈中的位置

HTTPS 不是一个新的传输协议,它只是在 HTTP 和 TCP 之间插入了一个 TLS 层

HTTP(应用层)
请求、响应、Header、Body——一切照旧
TLS / SSL(安全层)← 这一层就是 HTTPS 的核心
加密、解密、身份验证、完整性校验
TCP(传输层)
可靠传输、拥塞控制——也不变
IP(网络层)
路由、寻址

数据流是:HTTP 报文 → 交给 TLS 加密 → 再交给 TCP 传输。反过来,接收时:TCP 收到数据 → TLS 解密 → 还原为 HTTP 报文。

二、HTTPS 的底层支撑:SSL → TLS

1 从 SSL 到 TLS:同一个东西的进化

SSL(Secure Socket Layer,安全套接层)是 Netscape 公司在 1990 年代发明的加密协议。后来标准化为 TLS(Transport Layer Security,传输层安全)。

SSL 1.0
内部测试
SSL 2.0
1995
SSL 3.0
1996
TLS 1.0
1999(≈ SSL 3.1)
TLS 1.2
2008(主流)
TLS 1.3
2018(最新)
习惯叫法:今天大家说"SSL 证书"其实指的都是 TLS 证书。SSL 协议本身(SSL 2.0/3.0)已被废弃,但名字保留下来了。TLS 1.2(2008)至今仍是最广泛部署的版本,是兼容旧系统的"最低共同标准";TLS 1.3(2018)简化了握手流程(2-RTT → 1-RTT),废除了 RSA 密钥交换和不安全的旧算法,目前部署率已超 70%。本章通过 TLS 1.2 讲解完整的握手原理,并附 TLS 1.3 对比。

三、核心思想:非对称协商 + 对称通信

1 为什么是"混合"方案?

HTTPS 的设计面临一个两难问题:

加密方式优点缺点
对称加密
(加密和解密用同一把密钥)
速度,适合大量数据 密钥怎么安全地交给对方?
网络传输密钥会被窃听,当面给不现实
非对称加密
(公钥加密,私钥解密)
密钥分发安全,公钥可以公开传播 速度,不适合加密大量数据

HTTPS 的解法是取两者之长

用非对称加密来协商出一把对称密钥,然后用这把对称密钥来加密后续的所有通信内容。
非对称加密只干一件事——安全地传递"对称密钥的原材料";对称加密干剩下所有事——快速加密海量数据。以此达到性能和安全之间的平衡
2 形象比喻:保险箱传递钥匙

想象你要和远方的朋友安全通信:

1
朋友先寄给你一个打开的保险箱(公钥),钥匙他自己留着(私钥)
2
你写下一把普通锁的钥匙(对称密钥),放进保险箱,锁上
3
保险箱寄回去,只有朋友的私钥能打开
4
以后你俩都用这把普通锁(对称密钥)来锁箱子——又快又安全

保险箱(非对称加密)只用来传钥匙,真正的货物(HTTP 报文)用普通锁(对称加密)来保护。保险箱虽安全但笨重,普通锁虽简单但轻便。

四、HTTPS 连接的本质

1 两条连接,各司其职

HTTPS 通信分为两个阶段,不要混淆:

阶段名称职责时长
第一阶段 TLS 握手(Handshake) 验证身份 + 协商对称密钥 连接建立时执行一次
第二阶段 对称加密通信 用协商好的密钥加密/解密 HTTP 报文 持续整个会话
关键理解:HTTPS 连接建立了对对方的认知(你是谁?密钥是什么?),之后就不用每次传输数据都重新做一遍了。HTTP 把明文消息交给 TLS → TLS 用对称密钥加密 → 再交给 TCP 发送。HTTPS 连接本身不负责数据传输的稳定性——那是 TCP 的活。
2 数据流动路径
HTTP 报文
明文
TLS 加密
用对称密钥加密
TCP 传输
加密后的密文
互联网

发送是加密下行,接收是解密上行,路径完全对称

五、TLS 握手完整流程(8步详解)

1 握手概览(以 TLS 1.2 为例)

在发送第一条 HTTP 报文之前,客户端和服务器必须先完成 TLS 握手。以下描述的是 TLS 1.2 的 RSA 密钥交换模式,这也是目前最广泛部署的握手流程。整个过程可以浓缩为四句话:

  1. 客户端说:"你好,我能用这些加密方式,这是我的随机数"
  2. 服务器说:"你好,我选这个加密方式,这是我的随机数和证书"
  3. 客户端:验证证书 → 生成 Pre-Master Secret → 用服务器公钥加密后发给服务器
  4. 双方:用三个随机数算出对称密钥 → 后续全部加密通信
注意:TLS 1.3(2018)将握手简化至 1-RTT,废除了 RSA 密钥交换,仅保留 ECDHE。详见本章末尾的 TLS 1.2 vs TLS 1.3 对比。
2 第 1 步:Client Hello

客户端主动发起握手,发送一个 Client Hello消息。它虽然可以被看作"一个字节的数据",但实际上携带了丰富的协商信息

  • 支持的 TLS 版本列表:比如 TLS 1.2、TLS 1.3
  • 可选的对称加密算法(Cipher Suites):比如 AES-GCM、ChaCha20-Poly1305
  • 可选的非对称加密算法:比如 RSA、ECDHE
  • 可选的哈希算法:比如 SHA-256、SHA-384
  • 客户端随机数(Client Random):一个随机生成的、不容易被猜到的随机数
理解:Client Hello 就像是客户端在说:"我会说这些语言,用这些加密方式,你能配合哪种?另外,这是我的暗号(随机数),你记一下。"
3 第 2 步:Server Hello

服务器收到 Client Hello 后,做出选择并回应 Server Hello

  • 选定的 TLS 版本:从客户端列表里挑一个双方都支持的最高版本
  • 选定的加密套件(Cipher Suite):从客户端列表里挑一个最优的
  • 服务器随机数(Server Random):服务端也生成一个随机数

到这一步,客户端和服务端都拥有了相同的 TLS 版本、相同的加密套件、以及两个随机数(客户端随机数 + 服务器随机数)。

4 第 3 步:服务器发送证书

Server Hello 之后,服务器立即发送自己的证书(Certificate)。证书的核心作用是:

将服务器的公钥(以及公钥的签名)安全地发送给客户端。客户端收到后需要验证这个公钥是否真的是该服务器的合法公钥,而不是攻击者伪造的。

证书中的关键信息包括:

  • 服务器公钥(最核心)
  • 服务器主机名 / 域名(如 good.com
  • 证书签发机构(CA)信息
  • 证书有效期(起止时间)
  • 数字签名(CA 用自己的私钥对证书内容的哈希值做非对称加密的结果)
5 第 4 步:客户端验证证书(详解见第六章)

客户端收到证书后,需要做两重验证

  1. 验证证书签名链:确认这确实是 CA 签发的证书,不是伪造的
  2. 验证主机名:确认证书上的域名和自己正在访问的域名一致

验证通过后,客户端用服务器公钥加密一个Pre-Master Secret(客户端生成的第三个随机数),发送给服务器。

关键细节:生成证书签名的加密私钥并不是服务器公钥对应的服务器私钥!签名时,服务器公钥只是一个需要被签名的数据而已。真正用来生成签名的私钥是CA(证书签发机构)的私钥。客户端需要用CA 的公钥来验证这个签名——这引出了证书链机制(详见第六章)。
6 第 5–8 步:密钥生成与握手完成
步骤谁→谁内容
第 5 步 客户端 → 服务器 客户端生成 Pre-Master Secret(第三个随机数),用服务器公钥加密后发送
密钥生成 双方各自计算 用三个随机数(Client Random + Server Random + Pre-Master Secret)算出 Master Secret,再从 Master Secret 派生出四把密钥
第 6 步 客户端 → 服务器 "我将使用加密通信" + Finished(用协商好的密钥加密的校验消息)
第 7 步 服务器 → 客户端 "我将使用加密通信"
第 8 步 服务器 → 客户端 Finished
第 8 步完成后:握手正式结束。此后所有 HTTP 报文都用对称密钥加密传输。TLS 握手完成,HTTP 通信开始。
7 TLS 1.2 vs TLS 1.3 握手对比

以上 8 步是TLS 1.2(RSA 密钥交换模式)的完整流程。TLS 1.3(2018 年发布,RFC 8446)对此做了大幅简化,核心变化如下:

对比维度TLS 1.2(本章描述)TLS 1.3(2018)
握手往返(RTT) 2-RTT(两次来回,慢) 1-RTT(一次来回,0-RTT 会话恢复更快)
密钥交换方式 RSA(Pre-Master Secret)ECDHE 仅 ECDHE(前向安全性强制要求)
RSA 密钥交换被彻底废除
加密套件协商 客户端列出算法,服务器在 Server Hello 中选择 客户端在 Client Hello 中直接带上密钥参数(Key Share),服务器立即生成密钥
Change Cipher Spec 独立的步骤 5 和步骤 7 合并到 Finished 消息中,不再独立
证书加密 证书在握手中明文传输(可被嗅探) 证书在握手后半段用临时密钥加密传输
完整性保护 HMAC(加密和完整性分开,如 AES-CBC + HMAC) AEAD(加密和完整性合一,如 AES-GCM、ChaCha20-Poly1305)
废弃的旧算法 支持 RC4、3DES、CBC 模式等 全部移除,只保留安全的 AEAD 算法

TLS 1.3 简化后的握手流程:

客户端 服务器
1 Client Hello— 支持的版本 + 加密套件 + 客户端随机数 + Key Share(ECDHE 密钥参数)
2 Server Hello+ 加密证书 + Key Share+ Finished
双方各自用 ECDHE 算出 Pre-Master → Master Secret → 对称密钥(无需额外往返)
3 Client Finished— 握手完成,开始加密通信
仅 1-RTT,比 TLS 1.2 快了一个往返(约节省 50-100ms)
总结:TLS 1.3 的核心思路是"能省则省,能加密就加密"——减少往返(2-RTT → 1-RTT)、废除不安全算法(RSA 密钥交换、CBC)、证书也加密传输。目前 TLS 1.3 的部署率已超过 70%(截至 2026 年),但 TLS 1.2 依然是兼容旧系统的最低共同标准

六、证书与证书链:信任的根基

1 证书签名的验证机制

服务器证书上的签名(Signature)是这样生成的:CA 用自己的私钥对服务器证书内容的哈希值做一次非对称加密,得到密文——这就是签名。验证时反过来:

CA 私钥
加密
证书哈希值
签名(密文)

验证时:

签名(密文)
CA 公钥解密
得到哈希值 A
比对
自己算的哈希值 B
如果 A == B,证书内容未被篡改,公钥合法。签名本质上就是一种"防伪标签"——只有拥有 CA 私钥的人才能生成它。
2 证书链(Certificate Chain)

但客户端怎么拿到 CA 的公钥来验证签名呢?这引出了证书链

根 CA 证书(Root Certificate)
操作系统/浏览器出厂自带,无条件信任
中间 CA 证书(Intermediate CA)
由根 CA 签名,根 CA 用自己的私钥为中间 CA 的公钥担保
服务器证书(Server Certificate)
由中间 CA 签名,中间 CA 用自己的私钥为服务器的公钥担保

验证链路:用根 CA 公钥 → 验证中间 CA 的签名 → 得到中间 CA 公钥 → 验证服务器证书签名 → 确认服务器公钥合法。

为什么不需要无限递归?因为根证书是操作系统/浏览器出厂时预置的,被认为是无条件可信的。这些根证书由全球公认的 CA 机构持有(如 DigiCert、Let's Encrypt、GlobalSign 等)。

信任的终极问题:如果你的操作系统本身有问题(比如被恶意软件注入了假的根证书),那整个证书验证体系就崩塌了。你只能无条件相信你的操作系统预留的根证书。像支付宝这样的应用会自带根证书(证书绑定/Certificate Pinning),不依赖系统证书库。但根证书也确实存在腐败风险——历史上曾有 CA 违规签发证书,所以根证书并非 100% 安全。
3 中间人攻击:为什么必须验证主机名

即使证书的签名链验证通过,仍然可能有危险。考虑这个场景:

good.com 服务器
1拥有合法 CA 签发的证书
拦截
bad.com 攻击者
2散布节点拦截访问 good.com 的请求
3拿出自己的合法证书给客户端

你本想去 good.com,但请求被 bad.com的攻击者拦截。攻击者拿出自己的合法证书(由正规 CA 签发,确实属于 bad.com)给你验证。你验证证书签名——完全通过!因为证书本身确实是合法的。

关键结论:证书只证明"我是我",不保证"我是个好人"。它证明的是"持有此公钥的人确实拥有 bad.com 这个域名",而不是"这个网站值得信任"。

所以客户端验证的第二步是检查主机名:证书里包含了服务器的主机名和域名。客户端会比对证书上的域名和自己正在访问的域名是否一致。如果访问 good.com但证书上写的是 bad.com,浏览器就会报"证书不匹配"的警告。

更进一步:证书的签名是对整个证书所有信息的签名,不仅仅是服务器公钥。一旦证书中的主机名被篡改,哈希值就变了,签名验证就会失败。所以主机名是无法被篡改的——改了签名就对不上了。

七、三个随机数:为什么需要三个?

1 三个随机数分别是什么
随机数来源传输方式是否可见
Client Random 客户端生成 Client Hello 中明文发送 所有人可见
Server Random 服务器生成 Server Hello 中明文发送 所有人可见
Pre-Master Secret 客户端生成 用服务器公钥加密后发送 只有服务器能解密

三个随机数共同参与生成 Master Secret,再由 Master Secret 派生出最终的对称密钥。

2 为什么需要三个?—— 防御重放攻击(Replay Attack)

核心问题:如果只用 Pre-Master Secret 一个随机数来生成密钥,会怎样?

假设只用一个随机数生成密钥,那么相同的随机数 ⇒ 相同的密钥。这就引出了重放攻击

重放攻击场景(如果没有 Client Random 和 Server Random):

1. 你向服务器发送了一条加密消息:"给小明转账 100 元"
2. 攻击者虽然破解不了加密内容,但他可以把整段密文原封不动地录制下来
3. 几天后,攻击者把这段密文重新发送给服务器
4. 服务器解密后看到"给小明转账 100 元",以为是你的新请求,再次执行转账
5. 攻击者不断重放 → 你的钱不断被转出去

三个随机数的防御逻辑:

  • Client Random 和 Server Random 的作用:确保每次握手的密钥都不同。即使 Pre-Master Secret 碰巧相同,只要 Client Random 或 Server Random 不同,最终的密钥就不同
  • 每次 TLS 握手生成的 Client Random 和 Server Random 都是全新的,所以每次会话的对称密钥也是全新的
  • 攻击者重放旧的密文,服务器用当前会话的密钥去解密 → 解密失败(密钥不匹配)→ 丢弃
一句话:Client Random 和 Server Random 保证了密钥的一次性——每次握手生成全新的密钥,旧的密文在下次握手后就是废纸一张。攻击者可以录制,但重放不了

八、对称密钥的生成与双向加密

1 从 Master Secret 到四把密钥

三个随机数生成了 Master Secret,而 Master Secret 又通过密钥派生函数(PRF)进一步生成四把密钥:

三个随机数 → Master Secret
↓ 密钥派生(PRF)
客户端加密密钥 服务端加密密钥
客户端 MAC 密钥 服务端 MAC 密钥
密钥用途
客户端加密密钥客户端用它加密数据 → 服务器用它解密
服务端加密密钥服务器用它加密数据 → 客户端用它解密
客户端 MAC 密钥客户端用它生成消息认证码(HMAC)
服务端 MAC 密钥服务器用它生成消息认证码(HMAC)
2 为什么客户端和服务端用不同的加密密钥?—— 防御反射攻击

如果客户端和服务器用同一把密钥加密,会存在一个很损的攻击方式——反射攻击(Reflection Attack)

反射攻击场景(如果只用一把密钥):

1. 你给服务器发了一条加密消息:"分手吧"(其实你想说的是"不要分手啊")
2. 攻击者截获了这条密文
3. 攻击者把这条密文原封不动地发回给你(假装是服务器回复)
4. 因为双方用同一把密钥,你的客户端成功解密,看到"分手吧"
5. 你以为服务器真的说了"分手吧"——攻击者什么都没破解,却造成了破坏

双向不同密钥的防御逻辑:

  • 客户端用客户端加密密钥加密数据发给服务器
  • 服务器用服务端加密密钥加密数据发给客户端
  • 攻击者把客户端的密文扔回给客户端 → 客户端用服务端加密密钥解密 → 解密失败(因为这条密文是用客户端加密密钥加密的,不是服务端加密密钥)
一句话:两个不同的加密密钥确保了方向性——客户端发出的密文,连客户端自己都解不开。攻击者反射回来的密文在解密阶段就会失败。

九、MAC / HMAC:消息认证码

1 HMAC 是什么

MAC(Message Authentication Code,消息认证码)和 HMAC(Hash-based Message Authentication Code,基于哈希的消息认证码)是 TLS 完整性保护的核心机制。

HMAC = 带密钥的哈希算法。它在普通的哈希(SHA-256 等)基础上混入一个密钥,使得只有持有密钥的人才能生成和验证这个哈希值。
2 HMAC 的两大作用
作用说明对比数字签名
提取指纹 对消息内容生成一个"指纹"(哈希值),任何篡改都会导致指纹变化 相同,数字签名也能防篡改
验证拥有者身份 只有持有密钥的人才能生成正确的 HMAC。收到消息后验证 HMAC → 确认对方确实持有密钥 不同!数字签名可以公开验证(用公钥),HMAC 不能被公众验证(必须持有同一个密钥)
关键区别:HMAC 和数字签名都能验证身份,但数字签名可以被任何人验证(有公钥就行),而 HMAC 只有持有密钥的双方才能互相验证。在 TLS 中,HMAC 用于通信双方互相验证每条消息的完整性,而数字签名(证书签名)用于握手阶段让客户端验证服务器的身份。
3 HMAC 在 TLS 中的位置

TLS 的每条加密消息都附带一个 HMAC 校验值:

明文消息
加密密钥加密
密文
明文消息
MAC 密钥 + 哈希
HMAC 标签

密文和 HMAC 标签一起发送。接收方先用加密密钥解密,再用 MAC 密钥验证 HMAC——双重保障:别人看不到(加密),别人改不了(HMAC)。

十、TLS 握手与加密通信完整流程图

1 TLS 握手 8 步时序图
客户端 服务器
1 Client Hello— TLS版本 + 加密套件 + 客户端随机数
2 Server Hello— 选定加密套件 + 服务器随机数
3 服务器证书— 服务器公钥 + CA签名 + 主机名
客户端验证证书链 → 验证主机名 → 信任服务器
4 Pre-Master Secret— 客户端随机数,用服务器公钥加密
双方各自用三个随机数 → Master Secret → 四把密钥
5 Change Cipher Spec— 客户端:将使用加密通信
6 Finished— 客户端握手完成(加密的校验消息)
7 Change Cipher Spec— 服务器:将使用加密通信
8 Finished— 服务器握手完成
握手完成 → 后续全部用对称密钥加密 HTTP 报文
2 一次完整的 HTTPS 请求时间线
TCP 三次握手
TLS 握手
(8步,协商密钥+验证证书)
发送 HTTP 请求
(对称密钥加密)
接收 HTTP 响应
(对称密钥解密)

TLS 握手只在连接建立时做一次。之后的 HTTP 请求/响应都直接用对称密钥加密,TLS 层变成透明的加解密管道。如果开启了 TLS Session Resumption(会话恢复),后续连接甚至可以跳过完整握手,直接恢复之前的密钥。

十一、核心思想总结

四句话记住 HTTPS

  1. HTTPS = HTTP + TLS:HTTP 报文在传输前由 TLS 加密,收到后由 TLS 解密,HTTP 本身不变
  2. 非对称协商 + 对称通信:用慢但安全的非对称加密传递"对称密钥的原材料",用快但需要预共享密钥的对称加密处理海量数据
  3. TLS 握手 = 验证身份 + 协商密钥:证书验证回答"你是谁",三个随机数回答"我们用哪把密钥"
  4. 三个随机数 + 四个密钥:每次握手的密钥都不同(防重放),客户端和服务器各用各的加密密钥(防反射)

四重安全保障

保障机制防御什么
机密性对称加密(AES / ChaCha20)窃听——别人看不到内容
完整性HMAC(消息认证码)篡改——别人改不了内容
身份认证证书链 + 数字签名冒充——确认服务器真的是它声称的那个
防重放三个随机数(每次握手密钥不同)重放——旧的密文在新的会话中无效

需要记住的关键数字

  • 8 步:TLS 1.2 完整握手共 8 个步骤
  • 3 个随机数:Client Random + Server Random + Pre-Master Secret
  • 4 把密钥:客户端加密 + 服务端加密 + 客户端 MAC + 服务端 MAC
  • 2 重验证:验证证书签名链 + 验证主机名
  • 3 层证书链:根 CA → 中间 CA → 服务器证书

常见误解纠正

  • "SSL 和 TLS 是不同的东西" → 本质相同,TLS 是 SSL 的标准化后续版本
  • "证书验证通过 = 网站安全" → 证书只证明身份,不证明善恶
  • "HTTPS 加密了所有内容" → 域名和 IP 在 DNS 查询和 TCP 层仍然是明文
  • "根证书 100% 安全" → 根证书存在腐败风险,历史上曾有 CA 违规签发