题干与适用场景
一个全球 API 使用 TLS 1.3。请走读一次完整握手和一次恢复握手,解释各阶段加密了什么、证书如何认证服务器、密钥如何产生,并判断是否应该为 GET /rates 和 POST /transfers 启用 0-RTT。
主路径采用一组明确前提:客户端通过 TCP 连接 HTTPS 服务;服务器使用 X.509 证书认证;完整握手使用临时 ECDHE 密钥交换;恢复连接使用服务器在之前连接中签发的会话票据;API 入口可能是负载均衡器或 CDN。HTTP/3 会把 TLS 1.3 整合进 QUIC 连接建立,但本题先用 TCP 上的 TLS 记录说明消息顺序与安全属性。
这道题适合后端、客户端、基础架构、SRE、安全和通用软件工程岗位。完整作答需要回答三个工程问题:身份是怎样绑定到这次握手的、不同阶段的密钥保护了什么,以及减少一个往返为什么会引入应用层必须处理的重放风险。
面试官考察点
第一,候选人能否把密钥交换、身份认证和数据加密分开。证书中的公钥通常用于验证 CertificateVerify 对握手 transcript 的签名,不负责加密后续大量业务数据。对称流量密钥来自 ECDHE、PSK 和 HKDF 密钥计划。
第二,能否准确说出加密边界。初始 ClientHello 与 ServerHello 需要为协商提供信息;双方处理完 ServerHello 后可以得到握手流量密钥,后续的 EncryptedExtensions、Certificate、CertificateVerify 和 Finished 受到握手密钥保护。应用数据再使用独立的应用流量密钥。
第三,能否区分恢复连接与 0-RTT。会话恢复可以只缩短认证工作,仍按 1-RTT 完成握手;0-RTT 则允许客户端在第一个 flight 中发送 early data。两者都可能使用 PSK,但只有 early data 缺少基于本次 ServerHello 的新鲜性保证。
第四,能否把协议风险落实到业务语义。RFC 对 0-RTT 明确给出较弱安全属性:early data 不具备前向保密,并且无法保证跨连接不被重放。是否允许它,不能只看 HTTP 方法名,还要看请求是否会产生扣款、登录、计数、发券、使用一次性令牌等副作用。
第五,能否给出可验证的上线与排障方法。强回答会区分完整握手、1-RTT 恢复与 0-RTT,观察票据、ALPN、HelloRetryRequest、early data 接受或拒绝、HTTP 425 Too Early,并确认 TLS 在边缘终止后到源站是否还有独立安全通道。
回答前需要澄清的问题
- 传输协议是什么? TCP 上的 HTTPS 与 QUIC/HTTP/3 都使用 TLS 1.3 的密码学机制,但消息承载和连接时序不同。本题主路径按 TCP 说明。
- 是首次连接还是恢复连接? 首次连接没有可用 PSK,需要证书认证;恢复连接可以使用之前获得的票据,但不代表一定发送 0-RTT。
- 服务器是否要求客户端证书? 常见 Web API 只认证服务器;mTLS 还会加入客户端
Certificate与CertificateVerify。 - TLS 在哪里终止? 若在 CDN 或负载均衡器终止,客户端认证的是边缘端点。边缘到源站是另一条连接,需要单独讨论加密与身份。
- 业务操作的重放语义是什么?
GET /rates是否真的只读?它会不会消耗一次性令牌、增加计数或触发昂贵计算?POST /transfers是否有幂等键也不能自动消除所有 early data 风险。 - 客户端和服务端是否完整支持 HTTP early data? 客户端必须能在 early data 被 TLS 层拒绝或收到
425后,使用正常握手后的连接安全重试。
30 秒回答框架
“完整 TLS 1.3 握手中,客户端先发包含版本、密码套件和 ECDHE key share 的 ClientHello;服务器用 ServerHello 选定参数并返回自己的 key share。双方由 ECDHE 结果和握手 transcript 经 HKDF 派生握手密钥,因此 ServerHello 之后的扩展、证书、签名和 Finished 都被加密。客户端验证证书链、主机名和 CertificateVerify,再验证 Finished 并发送自己的 Finished,之后双方使用独立应用流量密钥。
恢复连接使用此前票据对应的 PSK,可以省去完整证书认证;若再启用 0-RTT,客户端可把 early data 与 ClientHello 一起发送。但 early data 只依赖 PSK,不具备前向保密,也可能跨连接重放。因此我只会让明确可重试、无副作用的读请求进入 0-RTT;转账请求必须等待握手完成,并支持 425 Too Early、统一网关策略和正常重试。”
分步骤深入解答
第一步:ClientHello 提供协商材料
客户端先发送 ClientHello。它通常包含随机数、支持的 TLS 版本、TLS 1.3 密码套件、签名算法、支持的密钥交换组、一个或多个 key_share,以及 SNI、ALPN 等扩展。TLS 1.3 密码套件主要选择对称 AEAD 算法和 HKDF 使用的哈希;证书签名算法与密钥交换组由其他扩展协商。
这条消息在普通 TLS 1.3 中尚未由握手流量密钥保护。SNI 也通常可见,除非客户端与服务器成功使用 ECH。回答“TLS 一开始就把所有字段加密”会忽略双方还没有从本次握手得到共同流量密钥。
客户端的 key share 是临时 ECDHE 公共值。对应私钥必须保持在本地,不能把公共值误称为“共享密钥”。双方最后通过各自私钥和对方公共值计算同一个 ECDHE 共享秘密。
第二步:ServerHello 完成参数选择和新鲜密钥交换
服务器选择 TLS 版本、密码套件和可接受的 key share,并发送 ServerHello。当使用 ECDHE 时,服务器也提供临时公共值。ClientHello 与 ServerHello 确定了本次连接的密码学参数,双方现在可以把 ECDHE 共享秘密送入 TLS 1.3 的 HKDF 密钥计划。
若客户端没有发送服务器可接受的 key share,服务器可以先返回 HelloRetryRequest,要求客户端用指定组再发一次 ClientHello。这会增加一个往返,而且原先尝试的 early data 不能直接按成功路径继续。线上看到握手偶发多一个 RTT 时,应检查是否发生了 HRR,而不是只归因于网络抖动。
从 ServerHello 之后,双方已经能派生 client/server handshake traffic secrets。协议把后续握手消息放在这些密钥保护下,所以被动观察者看不到证书和大部分扩展内容,但仍可观察记录长度、时序和未被 ECH 隐藏的初始信息。
第三步:服务器参数、证书与 transcript 签名建立身份
服务器随后发送加密的 EncryptedExtensions,其中包含对 ALPN 等 ClientHello 扩展的选择结果;如果需要客户端证书,还会发送 CertificateRequest。常见单向 HTTPS 接着发送服务器 Certificate、CertificateVerify 和 Finished。
三个消息承担不同职责:
| 消息 | 核心作用 | 常见误解 | |---|---|---| | Certificate | 提供服务器证书链及相关扩展 | 证书本身等于“握手已经可信” | | CertificateVerify | 用证书对应私钥签署当前握手 transcript | 证书公钥用于加密所有业务数据 | | Finished | 用握手派生密钥验证 transcript 完整性并提供密钥确认 | 只验证证书,不验证协商消息 |
客户端需要依据应用的 PKI 策略验证证书链、有效期、主机名以及允许的签名算法,再验证 CertificateVerify 的 transcript 签名。这样,服务器控制证书对应私钥的事实被绑定到本次 ClientHello、ServerHello 和协商参数,攻击者不能把另一次握手的签名直接搬过来。
第四步:Finished 完成握手,应用密钥与握手密钥分离
服务器的 Finished 是基于 transcript 和握手派生秘密计算的校验值。客户端验证成功后,确认自己看到的协商消息没有被篡改,并且对端拥有相同的握手密钥材料。客户端若不做证书认证或 Finished 验证就接受数据,会失去 TLS 的身份和完整性保证。
客户端随后发送自己的 Finished;如果服务器请求 mTLS,客户端还会先发送自己的证书与 CertificateVerify。双方为应用数据使用 application traffic secrets,而不是继续复用握手密钥。TLS 1.3 还支持通过 KeyUpdate 更新应用流量密钥,减少长期使用同一组流量密钥的范围。
前向保密来自临时 (EC)DHE:若双方删除临时私钥和不再需要的旧流量秘密,未来服务器证书私钥泄露不应解密之前抓取的完整握手会话。证书私钥负责认证,不能把“证书私钥安全”误当成前向保密的唯一来源。
第五步:会话票据把后续连接变成 PSK 恢复
完整握手后,服务器可以发送 NewSessionTicket。客户端保存票据和关联恢复秘密;下一次连接把票据标识作为 presharedkey 提议,并用 binder 证明自己拥有对应 PSK。服务器接受后,可以用 PSK 认证恢复连接,通常无需再次发送证书链和 CertificateVerify。
恢复不等于放弃新鲜 ECDHE。TLS 1.3 支持 PSK-only,也支持 PSK 与 ECDHE 组合。生产系统通常更关注 PSK+DHE:它保留恢复带来的认证与计算收益,同时让正常 1-RTT 应用数据包含本次连接的新鲜 Diffie-Hellman 材料。PSK-only 的安全属性不同,回答时应说明采用哪种模式。
票据也不是永久登录凭证。它有生命周期、绑定的密码参数、服务器密钥轮换和集群共享策略。多区域服务若不能一致解密或验证票据,会退回完整握手或拒绝恢复;这属于预期兼容分支,不应为了追求恢复率而无限延长票据密钥寿命。
第六步:0-RTT 把 early data 放进第一个 flight
若票据允许 early data,客户端可以在恢复连接的第一个 flight 中同时发送 ClientHello 和应用数据。early data 使用从 PSK 派生的 client early traffic secret 加密,发送时客户端还没有收到本次连接的 ServerHello。
这带来低延迟,也带来两个关键弱点:
- early data 只由 PSK 派生,不包含本次 ECDHE 交换,因此不具备前向保密。
- 它不依赖本次服务器随机数和
ServerHello,协议无法保证同一密文不会在另一条连接被重放。
服务器可以接受或拒绝整批 TLS early data。若拒绝,客户端必须在正常握手完成后重新发送仍需执行的请求。这个重试能力意味着应用本来就要面对“服务器可能已处理、客户端却没看到结果”的不确定性;0-RTT 又增加了攻击者主动制造跨连接重复的机会。
第七步:按业务副作用决定哪些请求可以提前处理
RFC 8470 在缺少额外信息时允许客户端对安全 HTTP 方法使用 early data,并禁止把不安全或安全性未知的方法放进去。不过方法名只是初筛,最终风险取决于资源行为。
| 请求 | 本题决策 | 原因 | |---|---|---| | GET /rates | 满足条件后可考虑 | 必须确认只读、可重复、无一次性令牌、无计费或不可接受的计算副作用 | | POST /transfers | 禁止使用 0-RTT | 重放可能导致重复转账、重复审计或不同时间的授权判断 | | POST /login | 通常禁止 | 会创建会话、消耗挑战或触发风控计数 | | GET /download?token=once | 禁止仅凭 GET 放行 | 一次性令牌和访问计数让它具有不可重复副作用 |
转账接口即使有幂等键,也不应因此直接开放 0-RTT。幂等存储必须在所有处理节点一致、在适当事务边界内原子生效,并覆盖审计、通知、额度与风控等副作用;幂等键本身还可能被窃取请求的重放持续占用。最稳妥策略仍是让此类操作等待握手完成。
第八步:在网关、源站和客户端之间建立一致策略
HTTP 为 early data 定义了 Early-Data: 1 与 425 Too Early。当网关把可能在上一跳 early data 中收到的请求转发给源站时,需要保留风险信号。源站若不能安全处理,应返回 425;客户端收到后应在握手完成的连接上重试,重试本身不能继续使用 early data。
边缘集群必须一致处理同类请求。若一个节点提前执行、另一个节点等待握手或拒绝,攻击者可能利用多实例差异让请求重复产生副作用。可采用的控制包括:
- 默认关闭 0-RTT,只对明确登记的只读资源开放。
- 限制票据寿命、early data 大小和可接受时间窗口。
- 使用共享或分区一致的 anti-replay 状态;承认它只能降低风险,不能替代应用语义。
- 在过载时整体拒绝 early data,避免重放放大昂贵请求。
- 确保 CDN、反向代理和源站都理解
Early-Data与425。
高质量示范回答
“我先按 TCP 上的 TLS 1.3、服务器证书认证和 ECDHE 完整握手回答。
客户端发送 ClientHello,提供支持版本、TLS 1.3 密码套件、签名算法、密钥交换组和临时 key share,也可能包含 SNI 与 ALPN。服务器用 ServerHello 选择参数并返回自己的 key share。双方由 ECDHE 结果和握手 transcript 经 HKDF 派生握手流量密钥,所以 key exchange 阶段结束后,EncryptedExtensions、服务器证书、CertificateVerify 和 Finished 都被加密。
证书提供服务器身份的信任链;CertificateVerify 用证书对应私钥签署本次握手 transcript,把这个身份绑定到当前协商;Finished 再证明 transcript 完整,并确认双方拥有同一握手密钥。客户端完成证书链、主机名、签名和 Finished 验证后发送自己的 Finished,双方改用独立的应用流量密钥。证书公钥负责验证身份签名,不负责加密所有业务数据;前向保密主要来自临时 ECDHE 和秘密擦除。
后续连接可以使用 NewSessionTicket 对应的 PSK 恢复。恢复可以是 PSK+DHE 的正常 1-RTT 握手,也可以选择 0-RTT。0-RTT 让客户端在 ClientHello 旁发送 early data,但这些数据只由 PSK 派生密钥保护,不具备前向保密,而且可能跨连接重放。
因此我不会让 POST /transfers 使用 0-RTT。即使接口有幂等键,转账、审计、额度和通知也必须共同证明重复执行安全。GET /rates 只有在确认它是纯读取、可安全重试、没有一次性令牌和不可接受副作用时才进入白名单。网关与源站要一致传递 Early-Data: 1,不安全时返回 425 Too Early,客户端在握手完成后重试。上线时我会分别测量完整握手、1-RTT 恢复和 0-RTT,并验证票据接受率、HRR、early data 拒绝路径和跨节点策略。”
常见错误
- 说证书公钥加密后续所有数据 → TLS 1.3 的业务数据使用对称流量密钥 → 说明证书签名验证、ECDHE/PSK 和 HKDF 的不同职责。
- 说从
ClientHello开始所有内容都已加密 → 初始协商发生在握手流量密钥建立之前 → 把加密边界放在ServerHello后的握手消息。 - 只验证证书链,不提 transcript → 身份还需要绑定到本次协商 → 解释
CertificateVerify与Finished分别验证什么。 - 把会话恢复等同于 0-RTT → 恢复可以正常等待 1-RTT → 先区分 PSK 恢复,再说明 early data 是可选能力。
- 认为 0-RTT 只是少一个 RTT,没有安全代价 → early data 不具备前向保密,也可能跨连接重放 → 把风险落实到应用副作用。
- 看到 GET 就自动开放 → GET 也可能消耗一次性令牌、记账或触发昂贵工作 → 按资源真实语义配置白名单。
- 认为幂等键自动解决转账重放 → 多节点一致性和外围副作用仍可能重复 → 高风险写操作等待握手完成。
- 只在 CDN 开开关关,不检查源站 → TLS 终止与 HTTP 转发跨越两个安全边界 → 统一边缘、网关、源站和客户端的
425处理。
追问及应对
追问一:TLS 1.3 为什么比 TLS 1.2 更快?
典型完整 TLS 1.3 握手可以在一个网络往返内完成参数协商和服务器认证,并移除了 TLS 1.2 中一些旧算法与多余消息。性能收益还来自更统一的密钥计划和恢复机制。不过总页面延迟仍包含 DNS、TCP、服务端处理和应用数据,不能把“TLS 1.3 是 1-RTT”误写成“请求一定只需 1 RTT”。
追问二:服务器证书私钥泄露后,历史流量会怎样?
若历史完整握手使用临时 ECDHE,而且实现已经删除临时私钥与旧流量秘密,仅泄露长期证书私钥不应解密之前抓取的应用数据。这就是前向保密的重要价值。若泄露的是票据加密密钥、PSK、会话秘密或端点上的流量密钥,影响范围不同,需要结合票据寿命、日志和密钥轮换评估。
追问三:为什么 anti-replay 存储仍不能让所有请求安全使用 0-RTT?
全局多区域系统很难在不增加延迟的情况下,对每个票据和 early data 做强一致、一次性接受。网络分区、节点状态、票据轮换和攻击者并发重放都会造成边界。协议层检测能限制成功重放的窗口或次数,但应用仍必须假设重复请求可能发生,并限制 early data 的业务范围。
追问四:如何验证线上到底走了完整握手、恢复还是 0-RTT?
在授权测试环境中,可用 openssl sclient -connect api.example:443 -servername api.example -tls13 -alpn h2 检查版本、证书和 ALPN;再保存并复用会话,观察是否恢复以及 early data 是否被接受。服务端应记录不含敏感内容的握手模式和拒绝原因。抓包若要解密,只能在受控环境使用客户端导出的会话密钥,并立即清理。
追问五:出现 425 Too Early 是故障吗?
不一定。它表示服务器不愿承担潜在重放风险,是 early data 的正常控制分支。客户端应在握手完成后自动重试,且重试不能继续使用 early data。若用户频繁感知失败,应检查客户端是否实现该重试、网关是否正确传递 Early-Data、不同节点策略是否一致,以及不适合的接口是否被错误加入 0-RTT 白名单。