代码 一个没人盯的握手消息:Go crypto/tls 拒绝服务漏洞分析

2026-09-01 21:02:46

一个没人盯的握手消息:Go crypto/tls 拒绝服务漏洞分析

先说结论:这不是一个需要特殊配置才能触发的 bug,默认情况下,凡是使用受影响 Go 版本编译的 TLS 服务端,都可能被一个格式合法、动作平凡的 TLS 1.3 握手消息打到 CPU 满载。

入口:KeyUpdate

TLS 1.3 引入了 KeyUpdate 消息,设计目的是让通信双方在不重新握手的情况下更新会话密钥。它是标准流程的一部分,本身没有任何"恶意"的外观。

在 Go 标准库 crypto/tls 的实现中,KeyUpdate 消息无论当前握手是否完成,都被视为"推进 TLS 状态机"的消息。问题就在这里:一个本应在握手完成后才出现、且应受次数限制的消息,在握手尚未完成时也被无条件处理

恶意客户端可以建立一个 TCP 连接,发送 ClientHello 后,不断发送 KeyUpdate 消息。服务端对每条消息都执行一次完整的 TLS 1.3 密钥派生(HKDF key derivation)运算。该运算是 CPU 密集型的,且实现中没有对 KeyUpdate 消息的接收次数或状态上下文做限制。结果是,攻击者用极小的带宽代价,换取服务端无上限的 CPU 消耗,形成典型的拒绝服务。

为什么默认就中招

因为这不是旁路逻辑,而是主握手路径上的问题:

  • 现代 Go 应用默认协商 TLS 1.3,无需任何额外配置;
  • KeyUpdate 是标准 TLS 1.3 会话流程的一部分,无法通过协议配置绕过;
  • 触发不需要认证、不需要应用层数据、不需要完成握手——只要连接建立,攻击就可以开始。

这意味着,你不需要跑在什么奇怪的边缘场景下。一个普通的 net/http 服务端,只要用了 TLS,就在暴露面上。

影响面从根因来看,取决于 crypto/tls 内部对 KeyUpdate 的状态校验逻辑。在该逻辑被修正前,所有使用受影响 Go 版本编译的服务端二进制都受影响,与部署方式(容器、裸金属、云 LB 后)无关。

影响版本

官方修复版本对照如下:

版本线修复版本
Go 1.25.xgo1.25.13
Go 1.26.xgo1.26.6
Go 1.27.xgo1.27.0-rc.3

受影响范围:

  • go1.25.13 之前的所有 Go 1.25.x;
  • go1.26.0-0 至 go1.26.6 之前;
  • go1.27.0-0 至 go1.27.0-rc.3 之前。

漏洞编号:GO-2026-6090 / CVE-2026-56862

CVSS 评分:7.5 HIGH

CWE 分类:CWE-770(无限制资源分配)

自查

检查你构建服务端二进制时用的 Go 工具链版本:

go version

如果输出落在上面的受影响区间内,那么该二进制内置的 crypto/tls 就存在此漏洞。这里要看的是编译时的 Go 版本,不是运行时容器的 base image 版本。

如果你在 CI 里统一管理 Go 版本,检查 CI 配置中的 go.mod 指令或工具链指定版本即可。

修复

升级 Go 工具链到以下任一版本及以上:

  • go1.25.13
  • go1.26.6
  • go1.27.0-rc.3

然后重新编译所有 Go 服务端二进制并重新发布。

没有官方 backport 机制。Go 只维护当前两条主要版本线,go1.25.13go1.26.6 分别对应两条线的修复。如果你用的是更老的 Go 版本,需要先升级到一条受支持的版本线,再升到对应修复版本。

运维层面:除了升级还能做什么

原文未提供官方临时缓解方案。 以下是从运维角度的分析判断,不作为官方规避手段。

  1. 网络层限速。在 LB/防火墙层面对单 IP 的新建连接速率做限制,可以降低攻击面,但无法根治:攻击者只要建立少量连接并持续发送 KeyUpdate,每个连接都会消耗服务端 CPU,限速只能延缓,不能阻止。

  2. 限制单连接时长/流量。在四层 LB 上对空闲连接或异常小流量长连接做超时断开,可以打断攻击者维持连接的行为。但对攻击者而言,重新建连成本很低。

  3. 不要关闭 TLS 1.3 作为临时方案。禁用 TLS 1.3 会强制降级到 TLS 1.2,改变整个加密配置基线,引入协议降级风险,并且并不保证后续 TLS 1.2 实现中没有类似问题。这不是一个可接受的缓解措施。

  4. 监控告警。关注服务端 CPU 突增和单连接高频握手消息的日志特征,有助于提前发现问题,但属于事后响应。

从实际效果看,升级是唯一彻底的修复手段。临时措施只能作为升级窗口期的缓冲。

小结

这个漏洞的本质是一个没有做好状态校验的握手消息处理路径:合法协议消息、无身份要求、无次数限制、CPU 密集操作、默认协议开启。不需要复杂的攻击链,几个 TCP 连接就能打满 CPU。

排查很简单,看 Go 版本;修复也很直接,升级重编译。不要在这个问题上做临时绕过的架构决策。

复制全文 生成海报 Go 安全 TLS 拒绝服务

推荐文章

程序员茄子在线接单