HTTPS 与 TLS 握手
面试回答: HTTPS 是 HTTP over TLS。HTTP 的方法、状态码和 Header 等语义基本不变,TLS 负责提供机密性、完整性和服务器身份认证,防止 HTTP 数据在传输中被窃听、篡改或由伪造服务器冒充。
以 TLS 1.3 首次完整握手为例,过程可以按下面六步回答:
- 客户端发送
ClientHello:声明支持的 TLS 版本、加密套件、SNI、ALPN,并通过key_share携带客户端临时 ECDHE 公开参数。这条消息通常明文发送。- 服务端返回
ServerHello:选择 TLS 版本和加密套件,并返回服务端临时 ECDHE 公开参数。ServerHello通常也是明文。- 双方派生握手密钥:客户端使用自己的临时私有参数和服务端公开参数计算共享秘密,服务端反向计算出同一个结果;双方再通过 HKDF 派生客户端、服务端两个方向的握手密钥。共享秘密和最终密钥都不会直接在网络中传输。
- 服务端证明身份:服务端使用握手密钥加密发送
EncryptedExtensions、证书、CertificateVerify(数字签名)和Finished。客户端按下面的依赖顺序验证:这三层验证逐层依赖,全部通过后,客户端才能同时接受服务端身份和当前连接。
- 证书链和域名校验通过 → 确认叶子证书中的公钥可以代表目标域名;
- 取得可信公钥 → 用它验证
CertificateVerify,确认当前服务端持有配对私钥,并把服务器身份绑定到本次握手;- 身份签名验证通过 → 再验证
Finished,确认服务端掌握本次握手密钥,而且双方看到的握手记录一致。- 客户端发送
Finished:服务端验证后,确认客户端也掌握正确的握手密钥,并且双方看到的握手记录一致,主握手完成。- 开始传输 HTTP:双方使用 HKDF 派生的应用流量密钥,通过 AES-GCM、ChaCha20-Poly1305 等 AEAD 对称认证加密算法保护 HTTP 请求和响应。
整体分工是:ECDHE 负责协商临时共享秘密,证书和数字签名负责认证服务器身份,HKDF 负责派生不同阶段和方向的密钥,AEAD 负责高效加密业务数据。证书私钥主要用于身份签名,不会逐段加密 HTTP。
记忆链路:
ClientHello→ServerHello→ ECDHE/HKDF → 证书认证 → 双方Finished→ AEAD 加密 HTTP。
1. HTTPS 到底解决什么问题?
假设浏览器准备访问:
如果使用明文 HTTP,浏览器和服务器之间的运营商网络、公共 Wi-Fi、代理设备等中间节点可能看到甚至修改传输内容。
所以可以先记住:
但“安全通道”有明确边界:TLS 保护数据在网络中传输的过程,不能修复服务端漏洞、跨站脚本攻击、弱密码、业务越权,也无法保护已经被控制的用户终端。
2. 握手前先认识几个角色
TLS 会同时使用多种密码学机制。先弄清它们各自负责什么,后面的握手就不会变成一串缩写。
2.1 对称加密:适合保护大量数据
对称加密的特点是:发送方和接收方使用同一把密钥,或者说双方持有相同的密钥材料。
它速度快,适合加密大量请求和响应。TLS 最终使用的 AES-GCM、ChaCha20-Poly1305 都属于对称认证加密算法。
“认证加密”表示它同时完成两件事:
- 加密数据,让旁观者看不懂;
- 生成认证标签,让接收方发现密文是否被修改。
对称加密的难题是:浏览器第一次连接 example.com 时,双方还没有共同密钥,不能直接开始加密。
2.2 非对称密码:公钥公开,私钥保密
非对称密码使用一对相关的密钥:
- 公钥可以公开给任何人;
- 私钥只能由持有者保存。
在现代 TLS 中,非对称密码主要做两件事:
- 数字签名:服务端使用“与服务器叶子证书中公钥配对的服务器私钥”对当前握手上下文签名;客户端从服务器叶子证书中取出“服务器公钥”进行验签。验签成功可以证明当前服务端确实持有与证书公钥配对的私钥,而不是仅仅复制了一张公开证书。服务器私钥始终保存在服务端,不会发送给客户端。
- 密钥协商:双方交换公开参数,在不发送最终会话密钥的情况下算出相同秘密。
这里不要把服务器密钥和 CA 密钥混在一起:
前者证明“当前服务端持有证书对应的私钥”,后者证明“这张证书确实由对应 CA 签发且内容没有被修改”。客户端还要继续检查证书路径、域名、有效期和用途,才能最终接受服务器身份。
因此,“非对称密码”不等于“用服务器公钥加密所有 HTTP 数据”。现代 TLS 不会让证书私钥逐段处理请求和响应。
为什么不直接用证书公钥加密所有 HTTP 数据?
更准确地说,不是所有非对称算法都能加密;即使某种算法可以,也不适合直接处理大量 HTTP 数据。
先看一种看似可行的设想:
这套方案至少有以下问题。
1. 证书中的公钥不一定具有“加密”能力
证书可以包含不同类型的公钥。RSA 公钥可以在合适的填充方案下用于加密,也可以用于验签;ECDSA 公钥则是用于验证数字签名的,不能拿来加密 HTTP 数据。
TLS 1.3 不要求证书公钥必须支持加密。它只需要证书密钥能够完成身份签名,因此不能把“证书中有公钥”直接理解为“这个公钥能加密业务数据”。
2. 非对称加密一次只能处理很少的数据
RSA 不能直接加密任意长度的消息。能加密的明文长度小于密钥模数长度,还要为安全填充预留空间。
例如,2048 位 RSA 密钥的模数长度是 256 字节;如果使用带 SHA-256 的 RSA-OAEP 安全填充,一次最多只能加密大约 190 字节。一个 HTTP 请求、JSON 响应、图片或 JavaScript 文件通常远大于这个大小。
理论上可以把数据切成很多小块分别做 RSA 加密,但这会产生复杂的分块、排序和错误处理问题,也会带来很大的密文膨胀,不能替代专门设计的安全记录协议。
3. 非对称运算比对称加密昂贵得多
非对称密码涉及大整数模幂或椭圆曲线运算,计算成本远高于 AES-GCM、ChaCha20-Poly1305 等对称算法。
如果每一小段 HTTP 数据都调用服务器证书私钥:
- 服务端 CPU 消耗会明显增加;
- 吞吐量和并发能力会下降;
- 长期私钥需要参与大量在线运算,扩大私钥相关实现的攻击面;
- 大响应需要执行大量非对称运算,失去实际可用性。
非对称密码适合处理少量关键材料和身份签名,对称密码才适合持续处理大量网络流量。
4. 服务器公钥只能自然解决“发给服务器”的方向
浏览器用服务器公钥加密请求后,服务器可以用自己的私钥解密。但服务器返回响应时,如果仍用服务器公钥加密,只有拥有服务器私钥的服务端自己能解密,浏览器反而无法读取。
要保护服务端到客户端的方向,还需要客户端提供自己的加密公钥,或者双方先协商一份共同密钥。普通 HTTPS 客户端通常没有用于网站身份认证的客户端证书;TLS 选择后一种方式:双方通过密钥协商得到共享秘密,再派生客户端和服务端两个方向的对称密钥。
5. 只做公钥加密不能自动得到完整的 TLS Record 安全性
安全传输不只是“把明文变成密文”,还需要:
- 检测密文是否被篡改;
- 区分客户端和服务端方向;
- 保证同一连接中的记录顺序;
- 防止旧记录被原样插回当前连接;
- 为每条记录正确构造唯一 nonce;
- 在需要时更新流量密钥。
直接对每块数据做一次公钥加密,并不会自动提供这一整套记录层语义。TLS 使用 AEAD 对称认证加密和记录序号共同实现这些能力。
6. 长期证书私钥泄露可能危及历史流量
如果历史 HTTP 密文一直是直接用服务器长期证书公钥生成的,攻击者可以先保存这些密文。未来一旦获得服务器证书私钥,就可能回头解密过去保存的流量。
TLS 1.3 使用临时 ECDHE 参数协商共享秘密。证书私钥只负责签名当前握手,不负责产生或解密应用数据密钥。因此,仅在未来泄露证书私钥,通常不足以恢复过去已经结束的 ECDHE 会话,这就是前向安全性。
所以现代 TLS 使用的是混合密码设计:
一句话记忆:
非对称密码解决“第一次见面时如何认证身份、建立共享秘密”,对称密码解决“建立连接后如何高效、安全地传输大量数据”。
2.3 密钥协商:不传输最终密钥,也能得到相同秘密
TLS 1.3 的完整证书握手通常使用 ECDHE。它是 Ephemeral Elliptic Curve Diffie-Hellman 的缩写,可以理解为“使用临时椭圆曲线参数的密钥协商”。
客户端和服务端各自生成一份临时私有参数,只交换对应的公开参数。然后:
最终的共享秘密没有在网络中传输。网络旁观者即使看到双方公开参数,也无法高效算出该秘密。
这里的 ECDHE 属于非对称密码学中的密钥协商,但不是“公钥加密、私钥解密”。
RSA 和 ECDHE 有什么区别?现在使用哪个?
RSA 和 ECDHE 不是完全相同类型的机制,不能简单理解成两个互相替换的“加密算法”。
- RSA 是一种非对称密码算法,可以根据具体方案用于数字签名,也可以用于加密少量数据。
- ECDHE 是一种临时密钥协商机制,只负责让双方得到相同的共享秘密;它本身不负责数字签名,也不能单独证明服务器身份。
“RSA 用于 TLS”有两种完全不同的含义:
前一种方式负责建立密钥,但长期 RSA 私钥未来泄露时,攻击者可能解开过去保存的握手流量,因此 TLS 1.3 已经移除静态 RSA 密钥交换。后一种方式只负责身份认证,在 TLS 1.3 中仍然可以使用。
因此,现代 TLS 1.3 完整证书握手通常是“组合使用”,而不是二选一:
例如,服务器完全可以持有 RSA 证书,同时使用 ECDHE 协商密钥:
如果使用 ECDSA 证书,则只是把身份签名从 RSA 换成 ECDSA,密钥协商仍然可以使用 ECDHE。会话恢复还可能采用 PSK-only 或 PSK + ECDHE,这属于后面的进阶内容。
所以面试中回答“现在使用哪个”时,可以说:
现代 TLS 1.3 的完整证书握手使用 ECDHE 等临时 Diffie-Hellman 机制协商共享秘密,不再使用静态 RSA 密钥交换;但 RSA 没有完全消失,它仍可以作为证书和握手的数字签名算法。典型组合是 ECDHE 负责密钥协商,RSA 或 ECDSA 负责身份认证,AES-GCM 或 ChaCha20-Poly1305 负责对称加密业务数据。
2.4 证书:把域名身份和公钥绑定起来
密钥协商只能让双方得到秘密,不能单独证明对方就是 example.com。主动攻击者也可以与浏览器协商一套密钥。
服务器证书大致表达:
什么是服务器叶子证书?
“叶子证书”不是一种特殊文件格式,而是证书在信任链中的位置。它也叫终端实体证书,是证书链最靠近具体网站、直接代表 example.com 的那一张证书。
可以把证书链画成:
从树形结构看,根 CA 在上方,具体网站证书位于没有下级分支的末端,所以叫“叶子证书”。在 TLS 的 Certificate 消息中,它通常是服务端发送的第一张证书。
它是一个什么样的存在?
叶子证书本质上是一份由 CA 数字签名的结构化公开数据。互联网 HTTPS 常用 X.509 证书标准。服务器配置中常看到 .crt、.cer 或 .pem 文件;它们可能采用二进制 DER 编码,也可能采用带有下面外壳的 PEM 文本编码:
文件扩展名和外层编码可能不同,但核心都是同一类证书结构。证书不是一段由人自由填写的说明文字,里面包含定义明确的字段,例如:
可以把一张叶子证书简化成下面这份“经过 CA 盖章的数据”:
叶子证书是公开信息,可以在 TLS 握手中发送给任何客户端。它包含服务器公钥,但绝不包含服务器私钥。实际部署中,证书文件和私钥文件通常分别保存:
为什么必须有叶子证书?
如果服务端只发送一个裸公钥,浏览器无法知道它属于谁。攻击者完全可以拦截连接,换成自己的公钥,并声称“这就是 example.com 的公钥”。
叶子证书解决的是“公钥属于谁”的问题:
- CA 在签发前按照规则验证域名控制权;
- CA 把
example.com、服务器公钥、有效期和用途等信息写入证书; - CA 使用自己的私钥对这些证书内容签名;
- 浏览器使用颁发者 CA 证书中的公钥验证签名;
- 浏览器继续沿证书链向上验证,直到本地已经信任的根 CA;
- 浏览器再检查访问域名是否匹配 SAN、证书是否有效;
- 最后通过
CertificateVerify确认当前服务端确实持有与叶子证书中公钥配对的服务器私钥。
因此,叶子证书不是独立完成信任的“万能身份证”。它需要同时满足:
CA 是 Certificate Authority,即证书颁发机构。操作系统或浏览器预置信任一些根 CA。服务端通常发送自己的叶子证书和必要的中间 CA 证书,客户端据此建立一条到本地受信任根证书的验证路径;根证书通常不由服务端发送,因为它是否可信必须由客户端本地信任库决定。
证书通常是公开信息。真正需要保密的是证书对应的私钥。
2.5 哈希、HMAC 和数字签名有什么区别?
哈希函数把任意长度的数据转换成固定长度摘要。输入只要发生很小变化,摘要通常就会明显不同。
HMAC 是 Hash-based Message Authentication Code,即基于哈希的消息认证码。它在哈希基础上加入双方共享的秘密密钥,用于确认“消息没有被修改,并且计算者掌握这把共享密钥”。
数字签名则使用非对称密钥:私钥签名,公钥验签。它可以把消息与某个身份私钥绑定起来。
2.6 各种机制在 TLS 中如何分工?
HKDF 是 HMAC-based Key Derivation Function,即基于 HMAC 的密钥派生函数。AEAD 是 Authenticated Encryption with Associated Data,即带关联数据的认证加密。现在只需要知道它们的职责,具体工作方式会在对应步骤中解释。
3. TLS 1.3 完整握手鸟瞰图
下面以首次访问 https://example.com/、只认证服务器的 TLS 1.3 连接为例。先假设域名系统 DNS 已经把域名解析成 IP,并且传输控制协议 TCP 已经完成建连。
两个关键分界点:
“明文”不代表攻击者可以成功篡改。前两条消息稍后会被纳入签名和完整性校验;攻击者修改它们,后续验证就会失败。
4. TLS 1.3 握手逐步拆解
每一步都回答四个问题:发送什么、为什么发送、此时双方拥有什么、消息是否加密。
第 0 步:连接前双方知道什么?
- 发送什么:还没有发送 TLS 消息。
- 为什么:先明确握手的起点。
- 此时拥有:浏览器知道目标域名、目标端口以及本地信任的根证书;服务端拥有站点证书和对应私钥。双方还没有本次连接的共享密钥。
- 加密状态:TLS 尚未开始。
浏览器还不知道对面是否真是 example.com,也不知道本次连接最终使用哪些算法和密钥。
第 1 步:客户端发送 ClientHello
ClientHello 可以理解为“客户端能力清单和第一次出价”。
- 发送什么:支持的 TLS 版本、加密套件、临时公开参数和部分扩展。
- 为什么:服务端需要从双方共同支持的能力中选择本次连接参数。
- 此时拥有:客户端已经生成临时私有参数,并只发送对应公开参数;双方仍没有握手密钥。
- 加密状态:普通 TLS 1.3 中通常明文发送。
常见字段第一次出现时可以这样理解:
传统 SNI 通常可被网络旁观者看到。如何隐藏它属于后面的进阶内容。
第 2 步:服务端返回 ServerHello
ServerHello 可以理解为“服务端确认核心参数,并给出自己的临时公开参数”。
- 发送什么:选定的 TLS 版本、加密套件、服务端随机数和
key_share。 - 为什么:只有服务端给出选择和公开参数后,双方才能确定核心算法并计算同一个共享秘密。
- 此时拥有:双方都拥有自己的临时私有参数和对方的临时公开参数,可以独立计算相同的 ECDHE 共享秘密。
- 加密状态:
ServerHello本身通常明文;处理完它以后,双方才能派生握手密钥。
简化理解:
服务端最终选择的应用层协议不会放在 ServerHello 中,而是在后续已加密的 EncryptedExtensions 中返回。
第 3 步:双方派生握手密钥
ECDHE 共享秘密只是原始密钥材料,不能直接拿来保护所有消息。TLS 需要把不同阶段、不同方向的密钥隔离开。
- 发送什么:这一步不发送新的消息,双方在本地计算。
- 为什么:需要从同一份共享秘密派生客户端和服务端各自方向的握手密钥。
- 此时拥有:双方可以得到相同的客户端握手密钥和服务端握手密钥。
- 加密状态:从下一条服务端握手消息开始,使用握手密钥保护。
这里使用前面提到的 HKDF。简化后的过程是:
“流量秘密”也叫 traffic secret,是继续派生具体密钥的秘密材料。“IV”是 Initialization Vector,即初始化向量;它会参与构造每条加密记录使用的唯一值。基础阶段只需要记住:traffic secret 还会继续派生出真正交给加密算法使用的密钥和 IV。
为什么要分方向?
“写密钥”是从发送方视角命名:把加密记录写入连接时使用。双方都能派生两组密钥,只是发送和接收方向相反。
第 4 步:服务端证明身份并确认握手
服务端接下来通常发送四类消息:
- 发送什么:上述协商、证书、签名和确认消息。
- 为什么:密钥协商本身不能证明对方身份,客户端还要确认“与我协商密钥的人就是
example.com”。 - 此时拥有:客户端验证通过后,既信任服务器身份,也确认双方掌握相同的握手密钥。
- 加密状态:这些消息都由服务端握手密钥保护。
证书和 CertificateVerify 是什么关系?
它们共同完成服务器身份认证,但职责不同:
服务端发送的 Certificate 消息中包含叶子证书和必要的中间证书。叶子证书包含服务器公钥、适用域名、有效期和用途,并带有 CA 的签名。客户端需要它来建立证书链并取得一个经过身份绑定的服务器公钥。
但是,证书本身是公开信息。攻击者可以从任何一次正常连接中复制 example.com 的证书,再原样发送给其他客户端。因此,只收到一张合法证书并不能证明当前连接的对端拥有对应私钥。
服务端接着发送 CertificateVerify:
如果攻击者只是复制了服务器证书,却没有服务器私钥,就无法为当前握手生成有效的 CertificateVerify。
因此,完整关系是:
为什么两条消息都要发送给客户端?
- 只发送证书:客户端能得到可信公钥,但无法确认当前对端持有对应私钥,因为证书可以被复制;
- 只发送
CertificateVerify:客户端看到一个签名,却不知道应该用哪个可信公钥验证,也不知道该公钥是否属于example.com; - 两者一起发送:证书建立“域名与公钥”的可信绑定,
CertificateVerify再把“私钥持有者”绑定到当前这次握手。
CertificateVerify 这个名字容易让人误以为它负责验证证书链。实际上,证书链由客户端使用 CA 公钥单独验证;CertificateVerify 是服务端生成、客户端验证的一条握手签名消息。
客户端如何验证证书?
客户端通常检查:
- 能否根据服务端证书和中间证书建立到本地受信任根证书的有效路径;
- 路径中的证书签名是否正确;
- 证书中的域名是否匹配
example.com; - 证书是否在有效期内,用途和浏览器安全策略是否允许;
CertificateVerify的握手签名是否正确。
证书路径建立对证书公钥的信任,域名校验确认该证书适用于 example.com,CertificateVerify 则证明当前对端确实持有对应私钥。这三件事不能互相替代。
transcript 是什么?
transcript 在这里指“截至当前的 TLS 握手消息记录”,可以把它理解为握手聊天记录。transcript hash 就是这些握手消息的哈希摘要。
实现通常维护持续更新的摘要,而不必反复保存和拼接全部消息。
CertificateVerify 和 Finished 有什么区别?
CertificateVerify 使用非对称数字签名:
它证明“服务端持有可信证书对应的私钥,并认可当前这次握手”。
Finished 使用从握手秘密派生的 finished_key 对 transcript hash 计算 HMAC:
它证明“服务端掌握本次握手密钥,并且双方看到的握手记录一致”。
一句话区分:
第 5 步:客户端发送自己的 Finished
- 发送什么:客户端根据自己的
finished_key和当前 transcript hash 计算出的验证值。 - 为什么:服务端也要确认客户端掌握正确的握手密钥,并且看到相同的握手记录。
- 此时拥有:服务端验证通过后,主握手完成;双方已经确认密钥和握手完整性。
- 加密状态:使用客户端握手密钥保护。
这里只做服务器身份认证,所以客户端没有发送客户端证书。使用双向 TLS 时,服务端也会要求客户端发送证书和 CertificateVerify。
第 6 步:使用应用流量密钥传输 HTTP
双方从截至服务端 Finished 的握手上下文派生第一代应用流量秘密,再得到不同方向的应用数据密钥和 IV。
- 发送什么:HTTP 请求和响应。
- 为什么:握手已经建立安全上下文,可以开始传输真正的业务数据。
- 此时拥有:双方拥有客户端方向和服务端方向的应用数据密钥。
- 加密状态:HTTP 内容使用 AEAD 对称认证加密。
时序上需要注意:服务端发送自己的 Finished 后就可以发送应用数据,不必等待客户端 Finished;客户端发送自己的 Finished 后才能发送普通应用数据。后文所述的 0-RTT(零往返早期数据)是例外。
在基于 TCP 的 HTTPS 中,HTTP 数据会被封装成 TLS Record,也就是 TLS 记录。记录层把连续字节流划分成可以独立保护的记录:
认证标签由加密算法根据密钥、密文和相关信息计算。接收方只有在标签验证通过后才接受数据;攻击者修改密文通常会导致验证失败。
5. 为什么这套流程能抵抗中间人?
如果只有匿名密钥协商,主动中间人可以分别与客户端、服务端建立两套密钥。HTTPS 的关键不是单独使用 ECDHE,而是把多种机制连接起来:
客户端和服务端的 key_share 等关键参数都会进入 transcript。中间人如果替换公开参数,就必须伪造可信服务器的握手签名和正确的 Finished,否则客户端会终止连接。
到这里已经足以应对普通前端面试中的 HTTPS 主流程。后面的内容用于回答网络、安全或高级后端岗位的深入追问。
6. 进阶理解
6.1 ECDHE 为什么能算出同一个秘密?
用椭圆曲线形式简化表示:
因为 abG = baG,双方得到同一个共享点。旁观者只能看到 G、aG、bG,无法高效推出 abG。
ECDHE 中的 E 表示 Ephemeral,即临时。每次完整握手生成新的临时参数,会话结束后不再需要这些临时私有参数。
这带来前向安全性:即使服务器证书私钥未来泄露,攻击者通常也不能仅凭过去保存的握手消息和密文恢复当时的 ECDHE 共享秘密。
6.2 HKDF 为什么还要分 Extract 和 Expand?
ECDHE 结果只是原始密钥材料。TLS 1.3 使用 HKDF 建立一棵密钥派生链:
简化后的两条主线是:
派生时加入标签和相应阶段的 transcript hash,可以实现阶段隔离、方向隔离,并把密钥绑定到当前握手上下文。
6.3 TLS Record 如何防止篡改和连接内重放?
TLS 1.3 的记录层会从 traffic secret 派生写密钥和 IV,并结合记录序号为每条记录构造 nonce。nonce 是 number used once,即单次使用的数值;同一密钥下不能错误地重复使用相同 nonce。
AEAD 根据密钥、nonce、明文和关联数据生成密文及认证标签。接收方维护自己的预期记录序号,构造对应 nonce 并验证标签。
因此,攻击者修改密文、修改被认证的信息,或者在同一连接中原样插入旧记录,通常都会导致验证失败。记录序号由连接两端维护,不需要作为独立字段直接发送。
6.4 TLS 1.2 与 TLS 1.3 有什么区别?
经典资料常把 HTTPS 描述成:客户端生成预主密钥(Pre-Master Secret),用服务器 RSA 公钥加密发送,服务端再用 RSA 私钥解密。这是 TLS 1.2 及更早版本允许的静态 RSA 密钥交换,不是 TLS 1.3 的流程。
TLS 1.2 也可以使用 ECDHE。此时证书私钥主要签名临时密钥参数,而不是解密客户端发送的预主密钥。
RTT 是 Round-Trip Time,即一次网络往返时间。下面的 RTT 只统计 TLS 握手,不包含 DNS 查询和 TCP 建连。
TLS 1.2 的套件名通常较长:
ECDHE:密钥协商;RSA:服务端使用 RSA 证书私钥进行签名认证;AES_128_GCM:对称认证加密;SHA256:参与密钥派生和握手校验的哈希算法。
TLS 1.3 把密钥协商组和签名算法放到其他扩展中单独协商,所以套件名更短:
6.5 会话恢复、PSK 和 0-RTT
PSK 是 Pre-Shared Key,即预共享密钥。首次完整握手后,服务端可以提供会话恢复信息;客户端下次连接时基于之前建立的 PSK 减少握手成本。
0-RTT 表示客户端可以在尚未收到本次 ServerHello 时,就在第一个发送批次中携带早期应用数据。它有两个关键弱点:
- 早期数据只由 PSK 派生的密钥保护,不具备前向安全性;
- 攻击者可能在另一条连接中重放早期数据,TLS 层无法为应用保证绝对的“只执行一次”。
支付、创建订单和修改状态等不能安全重试的操作,不应在缺少额外防重放设计时使用 0-RTT。
6.6 HelloRetryRequest 为什么会增加一次往返?
客户端提供的 key_share 不一定是服务端希望使用的参数组。服务端可以发送 HelloRetryRequest,要求客户端使用指定组重新发送 ClientHello 和新的 key_share。
因此,“TLS 1.3 完整握手通常是 1-RTT”不是绝对规则。重试消息也会以规定方式进入 transcript,不能被攻击者随意删除或修改。
6.7 HTTPS 保护什么,又暴露什么?
HTTPS 通常保护:
- HTTP 方法、路径和查询参数;
- 请求头、请求体、响应头和响应体;
- Cookie 在传输链路中的内容;
- HTTP 内容是否在链路中被修改。
但它不能隐藏所有网络元数据:
DoH 和 DoT 分别是 DNS over HTTPS 与 DNS over TLS,可以保护 DNS 查询链路。ECH 是 Encrypted Client Hello,即加密客户端问候,它尝试加密 ClientHello 中包括真实服务器名称在内的敏感内容。它们解决的是额外的元数据隐私问题,不改变 HTTPS 保护 HTTP 内容的核心结论。
6.8 HSTS 解决什么问题?
TLS 只能保护已经开始建立的 HTTPS 连接。如果用户最初访问 http://example.com,攻击者可能拦截 HTTP 跳转,让用户一直停留在明文 HTTP,这通常称为 SSL stripping。SSL 是 TLS 的历史前身,这个术语可以理解为“HTTPS 降级剥离”。
HSTS 是 HTTP Strict Transport Security,即 HTTP 严格传输安全。它让浏览器在发出网络请求前把 HTTP URL 升级成 HTTPS。HSTS preload 预加载列表还能减少首次访问尚未收到 HSTS 响应头时的暴露窗口。
HSTS 不是 TLS 握手的一部分,也不能忽略或修复证书错误。
6.9 HTTP/3 有什么不同?
HTTP/1.1 和 HTTP/2 通常在 TCP 上使用 TLS Record。HTTP/3 运行在 QUIC 上;QUIC 是一个基于 User Datagram Protocol(UDP,用户数据报协议)构建的安全传输协议,并把 TLS 1.3 握手集成进自己的连接建立过程。
HTTP/3 仍使用 TLS 1.3 的认证和密钥协商思想,但应用数据由 QUIC 的包保护机制承载,不再套用基于 TCP 的 TLS Record 层描述。
7. 高频面试追问
7.1 HTTPS 和 HTTP 是完全不同的应用层语义吗?
不是。HTTPS 主要是在 HTTP 外增加 TLS 安全通道,HTTP 方法、状态码、Header 和消息语义基本不变。
面试官为什么问: 判断是否只会说“HTTPS 比 HTTP 安全”。
7.2 为什么不能一开始就使用对称加密?
因为第一次连接时双方还没有共同密钥。TLS 先通过密钥协商得到共享秘密,再派生对称密钥。
面试官为什么问: 判断是否理解握手存在的根本原因。
7.3 为什么不用证书公钥加密所有 HTTP?
非对称密码计算成本高,不适合大量数据;现代 TLS 还需要认证加密和前向安全性。证书私钥主要用于身份签名,ECDHE 建立共享秘密,AEAD 才负责业务数据。
面试官为什么问: 判断是否理解非对称密码和对称密码的分工。
7.4 只收到一张服务器证书,为什么还不能立刻相信对方?
公开证书可以被复制。客户端还要验证证书路径、域名、有效期和用途,并通过 CertificateVerify 确认对端持有证书私钥。
面试官为什么问: 判断是否把“拿到公钥”误认为“建立身份信任”。
7.5 CertificateVerify 和 Finished 是否重复?
不重复。前者用证书私钥签名,证明身份私钥持有并绑定当前握手;后者使用握手密钥计算 HMAC,确认本次密钥和 transcript。
面试官为什么问: 判断是否理解身份认证与密钥确认的区别。
7.6 中间人为什么不能替换双方的 key_share?
因为 key_share 会进入 transcript。攻击者若替换它,就需要同时伪造可信服务器的 CertificateVerify 和正确的 Finished,否则验证失败。
面试官为什么问: 判断能否从主动攻击者视角解释 TLS 安全性。
7.7 抓包工具为什么能看到 HTTPS 明文?
常见原因是用户或系统信任了抓包工具生成的根证书。工具分别与浏览器和真实服务器建立两条 TLS 连接,相当于一个被本机主动信任的中间人。
面试官为什么问: 判断是否理解客户端信任库决定了谁可以代表目标域名。
7.8 TLS 1.3 是否一定是 1-RTT、一定使用 ECDHE?
不一定。HelloRetryRequest 会增加一次往返;PSK-only 恢复握手没有新的 ECDHE。
面试官为什么问: 判断是否把常见流程说成绝对规则。
7.9 为什么不能随意开启 0-RTT?
因为早期数据不具备前向安全性,并且可能跨连接重放。只能发送应用明确允许被重试的数据。
面试官为什么问: 判断是否理解性能优化的安全代价。
7.10 证书更新后部分用户仍报错,如何排查?
检查目标域名、证书有效期、完整中间证书链、SNI 下返回的实际证书、各服务节点是否一致、客户端时间和信任库,以及本地代理是否替换证书。
可以使用:
面试官为什么问: 判断能否把协议知识用于真实工程故障。
8. 常见错误回答
9. 面试时如何组织答案?
1 分钟版本:不依赖密码学术语
3 分钟版本:加入标准 TLS 术语
在 1 分钟版本上补充:
- 客户端发送
ClientHello,服务端返回ServerHello,确定版本、加密套件和 ECDHEkey_share; - 双方通过 ECDHE 得到共享秘密,再用 HKDF 派生分阶段、分方向的握手密钥;
- 服务端发送证书、
CertificateVerify和Finished,客户端验证证书路径、域名、私钥持有证明和 transcript; - 双方切换到应用流量密钥,用 AEAD 保护 HTTP 数据;
- 证书私钥用于身份签名,不直接加密业务数据,ECDHE 还提供前向安全性。
10 分钟版本:根据岗位方向展开
- 偏网络:RTT、Record、ALPN、HTTP/2、HTTP/3 与 QUIC;
- 偏安全:证书路径、中间人、前向安全性、0-RTT 重放和 HSTS;
- 偏后端运维:SNI、多证书部署、中间证书链、会话恢复和证书轮换;
- 偏密码学:ECDHE 数学性质、HKDF 密钥计划、transcript、AEAD nonce 和密钥更新。
不要把所有术语一次说完。先给完整主线,再根据面试官追问展开对应分支。
10. 术语速查
术语表用于复习,首次学习仍应结合前面的握手上下文理解。
11. 总结
- HTTPS 是使用 TLS 保护的 HTTP,提供机密性、完整性和服务器身份认证。
- TLS 1.3 主线是:协商参数、ECDHE 得到共享秘密、HKDF 派生密钥、证书认证、双方
Finished、AEAD 加密 HTTP。 ClientHello和ServerHello通常明文;处理完ServerHello后,后续大部分握手消息开始加密。- 证书路径和域名校验建立身份信任,
CertificateVerify证明对端持有证书私钥,Finished确认握手密钥和 transcript。 - 非对称密码负责密钥协商和身份签名,对称密码负责高效保护业务数据,HKDF 负责连接两个阶段。
- ECDHE 提供前向安全性;PSK-only 不提供新的前向安全性;0-RTT 还存在跨连接重放风险。
- HTTPS 保护传输通道,但不能替代应用鉴权、输入校验和其他安全防护。

