报告摘要
报告ID: #3463949
标题: AES-GCM 身份验证标签验证缺失与不当废弃处理
报告人: sideni 报告给: Node.js 报告时间: 2025年12月13日,UTC 下午4:49 状态: 已公开 (2025年12月19日) 严重性: 高 (8.2) 弱点: 缺少必要的加密步骤
漏洞详情
问题概述
在 Node.js 的 crypto 模块中,createDecipheriv 函数的文档指出:"authTagLength 选项默认为 16 字节,如果使用不同的长度,则必须设置为不同的值。"
然而,身份验证标签(authentication tag)的长度并未根据该默认值进行验证,可以被截断至 4、8、12、13、14 或 15 字节。这使得攻击者可以在修改密文后暴力破解身份验证标签,并恢复密钥材料,从而在之后离线计算更多身份验证标签。
影响与风险
这些经过身份验证的加密方案通常用于保护会话或令牌。攻击者可以利用此缺陷,通过更改有效密文并在服务器上暴力破解新的身份验证标签(最多需要约 12,884,902,656 次请求:(2**32) * 3 + 2 * 256)来获得有效的会话/令牌。
这还导致了 AES-GCM 的非重用(nonce reuse),从而泄露用于计算任何后续身份验证标签的密钥。请注意,不一定需要 120 亿次请求,因为攻击者可以利用截断的标签来恢复所需的密钥。
获得计算任意身份验证标签所需的密钥后,攻击者可以操纵密文进行解密并伪造新的密文。
废弃处理问题
我理解到,隐式使用较短标签长度的行为已通过某个 PR 被废弃。但是,废弃警告仅在标签实际短于 16 字节时才会发出。对于按照文档使用该函数(即期望 authTagLength 选项默认为 16 字节)的用户来说,除非攻击正在进行,否则永远不会看到警告。
复现步骤
以下脚本展示了默认的 16 字节 authTagLength 如何未被强制执行,从而允许隐式使用较短标签。同时,它也展示了废弃警告仅当攻击者截断身份验证标签(或明确截断标签,但这不是用户在未知危险中的场景)时才会显示。
复现代码:
|
|
观察废弃警告消息如何仅对后一种情况显示,以及被截断的身份验证标签如何成功允许解密(尽管“authTagLength 选项默认为 16 字节,如果使用不同的长度,则必须设置为不同的值。”)。
影响总结
- 密文可以被修改以解密为任意值。
- 通过观察解析差异可以解密密文(例如,如果解密后的数据预期是 JSON,则可以像填充预言攻击那样观察有效的/无效的 JSON 解析来解密密文)。
- 可以恢复 GCM 内部的 GHASH 密钥(用于计算更多任意身份验证标签,而无需暴力破解)。这需要轮换加密密钥。
考虑到
createDecipheriv函数的记录方式,这完全破坏了人们期望从此 API 获得的加密方案的完整性和机密性。
官方回应与处理过程
Node.js 团队成员 tniessen 回应 (2025年12月14日):
感谢报告。虽然同意当前行为不理想且文档可以改进,但这不幸是一个已知问题,并已在公开场合进行了广泛讨论。当前行为是由于 node:crypto 模块在许多方面紧密模仿 OpenSSL,包括这一点。虽然我们意识到这个问题已有一段时间,但由于某些应用程序依赖当前行为(即用户应用程序自行验证身份验证标签长度),我们无法在不经过废弃周期的情况下更改行为。
鉴于该行为已公开记录至少八年,认为无需将此已知问题视为漏洞。提议在 Node.js 的下一个主要版本中将其移至生命周期结束状态。
报告人 sideni 补充 (15天前):
不介意不将此问题视为漏洞。关切的是人们按照文档使用此功能却不知道自己面临风险。按照当前的废弃方式,只有依赖当前行为的用户知道它即将停止工作。其他人甚至不知道自己很脆弱。
即使不作为漏洞处理,也希望看到文档更新(添加警告等),或者废弃警告可以发给任何未在 createDecipheriv 上指定 authTagLength 选项的用户(而不仅仅是那些明确截断标签或正在被主动利用的用户)。感觉因为少数人使用有问题的行为而让大众保持脆弱很奇怪。
最终处理方案 (tniessen, 14天前):
- 将此报告作为信息性报告关闭。报告人可以请求公开披露此报告以提高透明度和可见性。
- 创建一个文档拉取请求,以更醒目地警告当前行为。这将在 Node.js 的下一个常规版本中可见。
- 创建一个拉取请求,将当前的废弃状态移至生命周期结束状态。这将在下一个主要版本中生效。
报告人 sideni 同意该计划。
报告状态更新:
- tniessen 将报告状态更改为“信息性”并关闭报告。
- 创建了文档 PR: https://github.com/nodejs/node/pull/61082
- 创建了生命周期结束 PR: https://github.com/nodejs/node/pull/61084
- sideni 请求公开披露此报告,tniessen 同意。报告已于 2025年12月19日公开。
附加信息:
- CVE ID: 无
- 赏金: 无