在没有 early data 的完整证书型 HTTPS 握手中,ClientHello 的 SNI 选择 TLS 配置与证书;稍后的 HTTP Host 参与请求路由。

SNI 让一个 IP 承载多个 HTTPS 站点

Server Name Indication(简称 SNI)在 TLS 握手中把目标主机名发给服务器,使同一个 IP 地址能够承载多张证书、多个站点。没有 SNI 时,分配不同地址是一种办法,却不是唯一办法:一张包含多个主体备用名称(SAN)的证书,或覆盖相应名字的通配符证书,也可以供多个站点共用。问题在于先后顺序:在不使用 early data 的完整证书型 HTTPS 握手中,服务器选证书发生在收到标识应用站点的加密 HTTP 请求之前,不能等读到 Host 再为这次握手换证书。 本文关注 nginx 的配置边界:哪个 server 块提供证书,名字没有匹配时采取什么策略,以及诊断命令究竟证明了什么。选中证书、客户端验证身份、把请求送到应用,是三个需要分别检查的决定,不能把其中一项成功当作另外两项也成功。 名字最先报出 客户端在 ClientHello 中携带 SNI,nginx 据此选择 TLS 服务配置。这个扩展使用已有的握手报文,不需要额外发送一次请求来询问站点。不过,把全过程说成“发生在加密之前”并不准确:TLS 1.3 在 ServerHello 之后加密证书报文。这里重要的是名字在证书选择时已经可用,而不是证书或整个握手始终明文传输。 客户端必须发送 SNI,服务器才能在这个阶段按名字选择站点。不带 SNI 时,nginx 从对应监听地址与端口的缺省服务配置开始处理;该配置可能提供证书,也可能拒绝握手。若收到证书,客户端仍需检查信任链以及自己预期的身份。收到一张证书不等于接受它,也不等于已经知道后续请求会进入哪个应用。 用 server_name 匹配 nginx 在相关监听地址和端口的 server_name 条目中匹配 SNI:精确名优先,然后是最长的前置星号通配名、最长的后置星号通配名,最后是配置顺序中第一个匹配的正则表达式。证书和私钥配置可以继承,也可以由多个站点共用;并不存在每个名字必须单独持有一张证书的规则。 ...

二月 7, 2028 · 2 分钟 · XB Field Notes
颁发方签名响应先被缓存,再由客户端检查,并标出有限的新鲜度时间轴。

OCSP 装订按客户端策略交付状态证据

OCSP 装订让 TLS 服务端在握手过程中发送签名的证书状态响应。对于原本需要在线查询 OCSP 的客户端,它可能省去一次单独请求。收益取决于客户端的吊销策略:并非每个浏览器每次连接都查询 OCSP,也不是每个证书颁发机构仍然提供这种服务。装订只是传递状态证据的一种方式,不能代替完整证书验证,更不能把“握手收到了一段数据”当作信任已经成立。 传递证据并不转移信任责任 服务器从颁发机构或获得授权的应答方取回响应,并为适用握手缓存它。客户端仍须检查响应签名、签名者权限、证书标识、状态和可接受时间范围。服务器把响应附在握手里,不会让它自动可信。OCSP 的 good 状态也不能证明主机名匹配、证书仍在有效期内,或整条证书链已经连接到受信任根。这些验证职责必须分别保留。 线上表示还取决于 TLS 版本。TLS 1.2 使用状态请求扩展与 CertificateStatus 握手消息;TLS 1.3 则把响应放在对应 Certificate 条目的扩展中。把两者统称为 certificate_status 扩展,会混淆实际协议结构。普通网络攻击者不能随意剥离受认证握手消息,同时仍让 Finished 校验成功。讨论吊销检查被绕过时,应明确攻击能力和客户端策略,而不是虚构一种可以无痕删除握手数据的能力。 先核对支持范围,再决定启用 运维者首先需要确认颁发方提供可用响应,并检查服务端及客户端是否支持预期策略。Let’s Encrypt 已在二〇二五年八月六日结束 OCSP 服务,改用证书吊销列表。因此,对于没有 OCSP 支持的证书,缺少装订不自动意味着刷新任务损坏。应查当前颁发方文档,而不是把“所有站点都应该打开装订”当成不需要前提的清单步骤。 对于仍提供 OCSP 的颁发方,应在缓存过期之前留出刷新余量,并覆盖证书轮换。需要检查响应对应哪张证书、新鲜度及边缘实际交付内容,而不只是缓存是否存在。不同服务进程可能持有不同结果;控制面抓取成功也不证明全部已更新。缓存中的 good 响应仍可能在可接受窗口内,而较新的吊销信息已经出现,因此装订不能提供瞬时吊销知识。 坏掉的样子 缺失、过期、无效和已吊销是不同状态。客户端可能拒绝连接、查询其他机制,或应用明确的软失败策略。缺少响应不保证触发直连颁发机构,已经提供但无效的响应也不保证仅仅增加延迟。描述时应说明具体校验器的行为,不要承诺所有握手都会继续,更不能把“没有报错”直接解释为吊销状态已经得到确认。 ...

十二月 6, 2027 · 2 分钟 · XB Field Notes
非对称默克尔树在左侧合并 A 与 B,右侧单独为 C,上方为可信根。B 是目标,A 与 C 依次为这棵固定合成树的证明节点。

证书透明度让签发可被观察

证书透明度 CT 让公开 TLS 证书的签发变得可观察,但它不判断域名持有者是否授权了某次签发,不代替证书链验证,也不保证世界上所有证书都已经进入日志。一张错误签发的证书也可能带有有效的透明度证据。真正的价值是留下公共线索,供监控方和受影响的持有者调查。 承诺不等于包含证明 SCT 即签名证书时间戳,是日志对已提交证书或预证书作出的签名承诺:在最大合并延迟 MMD 以内把它纳入树中。SCT 不是另一张证书,也不是证明条目已经存在于树中的包含证明。它的时间戳记录日志作出声明的时刻,不一定就是证书实际签发的精确时刻。 默克尔包含证明把某个已经序列化的叶节点,连接到特定大小的树及其根哈希。验证者需要通过相应的已签名日志声明和可信日志公钥认证这个根。如果无条件接受不可信证明一起附带的根,攻击者完全可以自己构造另一棵树;计算结果相同,也没有建立任何有用的外部事实。 一致性证明回答的是另一个问题:后来的树是否在保持既有前缀不变的情况下扩展了早先的树。一次包含证明不能说明全部历史。签名检查点、一致性验证,以及独立观察者之间对不同视图的比较,有助于发现日志向不同人讲述不同历史。哈希让修改可以被这些检查发现,不是物理上禁止运营者改写数据。 Chrome 对公开受信任的 TLS 证书执行自己的 CT 策略,考虑 SCT 的交付方式、日志状态、数量与运营者多样性。这不是每次打开页面都到公共日志里搜索,也不是判断持有者是否申请过证书。RFC 9162 定义了第二版协议并废止 RFC 6962,但规范发布并不能直接证明某个已部署日志实际支持哪一版。 坏掉的样子 SCT 的签名即使有效,如果对应日志不被接受、数量不足或交付方式不符合目标客户端策略,仍然可能无法通过检查。反过来,符合 CT 也修复不了过期、不受信任或名称不匹配的证书。普通 TLS 验证、CT 合规和签发是否获准,是需要分别确认的三个决定。 域名监控也需要结合业务背景解释。新记录可能来自获准接入的 CDN、通配符证书或正常续签;升级告警之前应核对签发者、名称、指纹与内部签发清单。无法解释的签发应进入调查和纠正流程,不能假定“已经写进日志”就代表它被阻止或被确认合法。 公开日志可能暴露证书中的名称,因此不应仅为做实验就提交私有证书或敏感内部命名。监控覆盖不全、数据过旧,也不能证明某次签发不存在。运营上的监控要声明范围和更新时间,不能把一次空搜索结果当成所有日志、所有时间都没有相关证书的保证。 快速验证 保存为 ct_probe.go,使用 Go 1.23 或更新版本运行 go run ct_probe.go。程序离线使用 RFC 6962 的 SHA-256 默克尔构造,输入是三个合成字符串,不是真实证书,也不是已经按 CT 协议序列化的叶节点。它只验证这个固定三叶树中下标为一的中间叶节点,不是通用验证器。 ...

十一月 3, 2027 · 2 分钟 · XB Field Notes
时间轴区分过去经过正确认证的新鲜 ECDHE 会话与日后长期签名私钥失窃。在临时机密没有一起被获取的前提下,仅靠该长期私钥不能恢复先前会话机密。

TLS ECDHE 的前向保密边界

前向保密限制的是长期认证密钥日后泄露造成的影响。对于经过正确认证的临时 Diffie-Hellman 交换,攻击者仅取得长期认证私钥,不能据此恢复先前的会话机密。前提是临时机密没有一起被获取;它不会让已经被攻破的端点、导出的密钥日志或保存下来的明文突然变得安全。 新鲜协商、身份认证和密钥派生各司其职。前向保密只限制特定的长期签名私钥日后泄露场景,并不保护已经暴露的会话机密或被攻破的端点。 两类密钥承担不同职责 ECDHE 中,双方分别生成临时私钥并交换公开份额。每一方把本地私钥与对方公开份额组合,得到相同的共享机密。旁观者虽然能看到公开份额,但在算法的安全假设成立时,缺少重现计算所需的私有值。新鲜的交换材料并不是双方在网络上公开商量出的一段秘密口令。 TLS 也不会把原始 ECDH 输出直接当成应用加密密钥。密钥调度还会派生不同的握手与应用流量机密,绑定握手上下文,并区分方向和用途。临时交换只提供其中一项关键材料,不能用“双方算出相同字节”替代整个传输协议,也不能略过后续派生和认证步骤。 证书按照信任规则把身份绑定到公钥,实际签署握手材料的是对应的私钥,不是证书这个数据对象自己在签名。TLS 1.3 的证书认证路径通过 CertificateVerify 认证握手记录。如果没有身份认证,主动中间人可以替换公开份额,分别和两端建立自己的共享机密;仅仅看到加密正常,并不能排除这种攻击。 RSA 或 Ed25519 认证密钥可以与临时交换并存,签名算法和密钥交换组是不同选择。TLS 1.3 还定义了仅使用 PSK 的恢复模式,后者不具备 DHE 带来的这项前向保密;PSK 配合 DHE 则会加入新的交换材料。可选 early data 的保证更弱,因此不能单凭 TLS 版本或证书算法标签,就推断所有阶段的流量都有相同保护。 ...

十月 27, 2027 · 2 分钟 · XB Field Notes
TLS 边界保护客户端到解析器的连接。所选解析器能读取 DNS 问题,后续递归不会自动加密。

DoT 与 DoH 保护通往已认证解析器的连接

DNS over TLS 和 DNS over HTTPS 保护其端点之间加密连接上的 DNS 流量。对于典型客户端,这条连接终止于选定解析器;解析器能够读取问题与回答,它随后发出的查询还可能使用不同传输。加密这一跳,不会自动加密整个递归过程,也不会让解析器失去记录所处理名称的能力。隐私范围应按真实连接边界说明,而不是笼统称为整个 DNS 都已保密。 分别观察加密边界与认证证据。853/443 为常用协议端口;8531/8443 属于文章的回环实验。证书失败诊断不能被零退出码掩盖。本图仅依据来源制作:加密 DNS 运行审阅仍待完成,实验未重跑。 坏掉的样子 加密套接字如果没有按预期验证证书,也可能连接到错误端点。应同时验证证书信任链和客户端期望的解析器身份;握手成功本身不能证明这两项检查已启用。失败时悄悄改用其他解析器或明文路径的配置,也会改变隐私契约。需要通过真实调用方了解这些行为,不能只看到配置文件中有一个 TLS 或 HTTPS 地址,就认定所有查询都符合预期。 DoH 使用 HTTPS,但四百四十三端口不会让它在所有网络中都无法识别、无法阻止或完全等同于任意网页流量。目的地址、连接时间和其他元信息仍可观察,TLS 终止点还可以检查明文 HTTP。选择解析器和传输策略时,应考虑这些边界,不能假定 HTTPS URL 会消除所有与 DNS 活动有关的信息暴露,也不能由加密推导解析器不会保存日志。 ...

十月 7, 2027 · 3 分钟 · XB Field Notes
可信客户端证书与私钥持有证明通向独立的应用授权分支:reader 获准访问并返回 HTTP 200,合法 guest 被拒绝并返回 HTTP 403。软件私钥可以被复制到别处使用,硬件身份需要额外机制。

客户端证书认证私钥控制能力

双向 TLS 在验证服务器身份的同时,也认证客户端是否能够使用证书对应的私钥。但它并不天然证明某台物理设备的身份。可复制的软件私钥可以被带到别处使用;硬件绑定和设备证明需要额外机制。注册和签发策略可以把密钥关联到设备,但 TLS 本身不会自动建立或验证这项硬件关联。 mTLS 认证私钥控制能力。应用根据已验证身份另行授权,因此有效凭据仍可能得到 403。物理设备身份与凭据生命周期还需要额外控制。 完成认证仍然需要授权 TLS 1.3 的证书式客户端认证中,服务器请求证书,客户端通过 CertificateVerify 证明自己能够使用对应私钥。只发送一份公开证书文件并不够。双方都必须应用各自的信任规则,检查证书链和适当用途;客户端还要验证服务器名称,不能因为自己提交了凭据就放弃验证对端。 服务端信任哪些客户端 CA,与客户端信任哪些服务器 CA,是两个方向的决定。应只接受预期签发者,并明确使用哪个已验证证书字段表示工作负载身份。URI SAN 可以存放应用标识,但谁有资格拿到这个标识,取决于签发者的注册规则。证书里出现了名字,不代表它自动拥有所有 API 权限。 “要求必须提供证书”也不同于“请求对方有的话就提供”。Go 的 RequireAndVerifyClientCert 要求有效客户端证书,而可选模式可能允许没有证书的连接通过。认证之后仍需根据已验证身份执行授权,因此合法访客可以得到 HTTP 403,而获准读取的客户端得到 HTTP 200,这两个结果不矛盾。 ...

九月 6, 2027 · 3 分钟 · XB Field Notes
TLS 1.3 完整与恢复握手卡片都标明:无早期数据时通常需要一次 TLS 往返。完整握手使用证书认证,恢复接受 PSK 认证并更新密钥。可选零往返数据仍可被重放。

TLS 1.3 会话恢复复用认证状态

“省一次往返”需要结合协议版本和 early data 模式理解。TLS 1.3 的普通完整握手,以及不携带 early data 的恢复握手,通常都需要一次 TLS 往返。恢复仍然可以减少证书传输和身份认证开销,但开启票据并不意味着每个 HTTPS 请求都能提前一个 RTT 开始。 TLS 1.3 会话恢复在新连接上复用认证状态,并派生新的流量密钥。普通恢复不保证省一次往返;可选早期数据还需要单独处理重放、前向保密与拒绝边界。 新连接仍要派生新的流量密钥 TLS 会话恢复使用先前握手派生的 PSK,为一条新连接建立安全上下文。NewSessionTicket 提供的是与恢复状态关联的不透明标识,不是让后续连接直接沿用原来的流量密钥。新的握手仍会根据自身上下文派生密钥。服务器可以用密码学方法保护票据状态,也可以在不透明标识后保存服务端状态;应用不应把票据解析成一种通用登录凭据。 服务器接受 PSK 认证时,不再发送自己的 Certificate 和 CertificateVerify 消息。恢复可以结合一次新的临时 Diffie-Hellman 交换,获得相应的前向保密;协议也允许仅使用 PSK 的模式,后者没有这项保护。因此,“拿到了票据”既不能证明实际选用了哪种密钥交换,也不能独自证明节省了多少网络等待。 ...

八月 8, 2027 · 2 分钟 · XB Field Notes
三条 TCP 轨道上有四个请求。cold 与 reuse 共用连接 1,新握手分别为一次和零次;resume 在连接 2 恢复一次握手,no cache 在连接 3 完整握手一次。

TLS 握手会拉长延迟,但可以缩小

HTTPS 延迟由多个阶段组成,重复访问可以跳过其中一些阶段,却不一定是加密运算本身变快了。DNS、获取连接、TCP 建连、TLS 认证、服务端处理和响应传输,各自有不同的计时边界。分析前应先确认哪些阶段真的执行过;单看一次请求总耗时,无法区分复用既有连接与新连接上的 TLS 会话恢复。 消息会按批次传输 TLS 握手虽然包含多条消息,但并不是每条消息都需要单独一次往返,多条消息可以在同一批次中发送。通常的 TLS 1.3 完整握手在普通客户端应用数据之前需要一次 TLS 往返,HelloRetryRequest 会再增加一次。TCP 建连和之后的应用请求、响应,还属于另外的成本。 不使用 early data 的普通 TLS 1.3 会话恢复,通常也需要一次 TLS 往返。它能减少证书传输与认证工作,却仍可能执行新的临时密钥交换;恢复时派生的是新流量密钥,不是原封不动继续使用旧加密密钥。可选零往返数据有额外的重放安全限制,不能把一次快速重复请求直接叫作零往返。 HTTP 连接复用则跳过了建立另一条连接的步骤,因此该请求没有新的 TLS 握手。HTTP/2 多路复用也可以让多个流共享已建立连接。相反,关闭空闲连接再重新连接,即使缓存票据允许 TLS 恢复,仍然需要重新完成传输层建立,不能把两种节省混成同一个动作。 坏掉的样子 正常请求若每次创建新的 transport,就会丢掉连接池。响应正文没有读完或关闭,也可能妨碍复用。空闲超时、入口变化或并发需求都可能增加新连接数量,因此在把延迟变化归因于证书算法之前,应先按真实复用情况和握手事件分类,确认自己比较的是同一种路径。 尝试恢复后仍发生完整握手,并不必然意味着服务故障。票据可能过期或被拒绝,客户端也可能没有可用缓存。应保留普通证书验证,并观察最终选择的行为;为赢得性能数字而减少认证检查,改变的是安全约定,不是在同一个操作下获得了免费优化。 计时名称也要有定义。首字节时间包含的不只有 TLS,总时间还包括消费响应内容。跟踪回调可能来自不同协程,收集器必须正确同步。应比较有代表性的分布及连接类别,不能拿几次回环请求的微秒数去预测公网加速,也不能把偶然更快的一次执行写成稳定性能承诺。 快速验证 保存为 latency_probe.go,使用 Go 1.23 或更新版本运行 go run latency_probe.go。实验固定使用经过验证的 TLS 1.3 和 HTTP/1.1,服务端为接受的 TCP 连接编号。第一个 transport 同时保留 HTTP 连接池和 TLS 会话缓存,另一个独立 transport 刻意不配置会话缓存。 ...

六月 28, 2027 · 3 分钟 · XB Field Notes