Hotdry.
security

代码审计视角:密码学实现中的草率错误与工程化防御实践

通过 Trail of Bits 对 aes-js 与 pyaes 库的审计案例,揭示密码学实现中的关键缺陷与侧信道防御策略。

在密码学领域,一个常见的误解是:只要算法选择正确且密钥足够强壮,系统就能保证安全。Trail of Bits 于 2026 年 2 月发布的一篇审计报告深刻揭示了一个残酷现实 —— 即便是广为使用的密码学库,其接口设计中的「便利性」考量也可能成为安全防线的致命突破口。本文将从这起审计案例出发,系统梳理密码学实现中的典型草率错误,并给出可落地的工程化防御建议。

密钥与初始化向量的重用陷阱

审计报告的核心发现指向了 aes-js 与 pyaes 这两个流行 AES 库在 CTR 模式下的默认初始化向量(IV)行为。当开发者调用这些库的 AES-CTR 模式时,如果未显式提供 IV,库会自动填充一个固定值 0x00000000_00000000_00000000_00000001。表面上看,这是降低使用门槛的「友好」设计;但在密码学安全视角下,这等同于在系统中埋下定时炸弹。

CTR 模式的工作原理是将 nonce(此处即为 IV)与递增计数器拼接后作为块密码的输入,再将输出与明文进行异或操作以产生密文。当两个不同的明文使用相同的密钥和 nonce 加密时,攻击者可以通过简单地异或两个密文来恢复明文的异或值。在现实攻击场景中,这意味着攻击者无需掌握任何密钥材料即可还原敏感信息的核心部分。Trail of Bits 在报告中引用了二战时期 Venona 项目对苏联密码系统的破解作为类比 —— 密钥重用的危害程度可见一斑。

更值得关注的是这种设计缺陷的生态影响。npm 包管理器显示,仅 aes-js 就有超过 850 个直接依赖项;而 GitHub 的统计表明,约 70 万个代码仓库集成了 aes-js,近 2.3 万个仓库集成了 pyaes。大量开发者直接复制库文档中的「简化示例」进行开发,无意中继承了这一密钥重用缺陷。这不是某个项目的小概率失误,而是一个系统性风险。

侧信道攻击面:查找表与填充时序

除密钥重用问题外,审计还揭示了这两个库在其他维度的安全隐患。首先是侧信道攻击风险:aes-js 与 pyaes 均使用查找表(lookup table)方式实现 AES 的 S-box 变换。这种实现虽然在计算效率上具有一定优势,但极易成为缓存时序攻击(cache-timing attack)的目标。攻击者可以通过测量缓存访问时间推断出 S-box 的部分内容,进而恢复密钥。现代安全实现通常采用常数时间(constant-time)算法或硬件加速方式来规避这一风险。

其次是填充时序漏洞。PKCS#7 填充验证代码中存在可被利用的时序差异,在 CBC 模式下可能演变為经典的填充 oracle 攻击。攻击者通过逐步探询填充验证的时间响应,能够以每字节约 128 次尝试的效率逐字节解密任意密文块。这一发现意味着即使用户正确生成了随机 IV,仅因库实现缺陷,系统仍可能面临被攻破的风险。

现代认证加密模式的缺位

审计报告还指出了一个更为根本的设计缺陷:这两个库完全不支持 AES-GCM 或 AES-GCM-SIV 等现代认证加密模式。在大多数安全应用场景中,单纯加密(encryption without authentication)是不够的 ——CTR 模式产生的密文具有可塑性(malleability),攻击者可以任意修改密文中的特定比特,相应地,明文中也会有完全相同的比特发生改变,且这种篡改无法被检测。

这种缺乏认证的风险在特定场景下可能引发严重后果。例如,若系统使用 ECDSA 签名,攻击者可能通过修改包含签名请求数据的密文,诱导签名者使用一系列相关的密钥进行签名,最终可能恢复出 ECDSA 私钥。GCM 和 GCM-SIV 模式通过计算加密数据的认证标签(authentication tag)来防止此类篡改 —— 任何密文修改都会导致标签验证失败,从而拒绝解密被篡改的数据。

两种响应范式:草率与匠心

审计过程中,一个有趣的对比浮现出来:当安全研究员向 aes-js 和 pyaes 的维护者报告上述问题时,得到的回应仅是一句「yadda, yadda, yadda」—— 将严肃的安全隐患轻描淡写为无关紧要的技术细节。更令人担忧的是,该库自 2018 年起再未更新,安全问题长期悬而未决。

形成鲜明对比的是 strongMan VPN 管理套件的响应方式。strongMan 是 strongSwan VPN 套件的 Web 管理界面,使用 pyaes 加密存储在 SQLite 数据库中的私钥和证书,同样受到了默认 IV 问题的影响。Trail of Bits 私下向项目报告该问题后,维护者 Tobias Brunner 立即创建了安全修复分支,并与审计团队协作制定了全面的补救方案。

strongMan 的修复策略体现了真正的「匠心」:首先,将 pyaes 替换为支持现代加密模式的库;其次,将 CTR 模式迁移至 GCM-SIV,引入内置认证机制;第三,在解密流程中集成标签验证;最后,采用每条目密钥派生方案,确保不同数据项使用不同的密钥和 IV,完全消除密钥重用的可能性。此外,项目还提供了数据库迁移脚本,帮助现有用户平滑升级到安全版本,并发布了完整的安全公告。

工程实践建议

从这起审计案例中,我们可以提炼出若干可操作的工程实践建议。第一,在密码学库选型时,优先选择强制要求 IV/nonce 参数的 API 设计,避免任何形式的默认值 —— 宁可在调用时增加一行随机数生成代码,也不要依赖库的「便利」特性。第二,对现有系统进行审计时,应将「参数可选」的设计模式列为高风险检查项,特别是加密库的初始化参数。第三,迁移至支持认证加密的模式(如 GCM、ChaCha20-Poly1305),而非单独使用加密和 MAC 的组合。第四,审查实现中是否存在基于查找表的密码学操作,考虑替换为常数时间实现或使用硬件加密支持。

密码学实现从来不是「一次正确」就万事大吉的领域 —— 它需要持续的关注、审慎的决策,以及对潜在风险的主动防御。选择匠心而非草率,是每一位密码学实践者的必修课。

资料来源:Trail of Bits 博客文章《Carelessness versus craftsmanship in cryptography》(2026 年 2 月 18 日)。

查看归档