rustc 安全公告 (CVE-2021-42574)

2021年11月1日 · Rust 安全响应工作组

这是官方安全公告经过轻微编辑的交叉发布。官方公告中也包含我们 PGP 密钥的签名版本。

Rust 安全响应工作组收到了一份关于包含“双向覆盖”Unicode 码点的源代码的安全担忧报告:在某些情况下,使用这些码点可能导致代码审查时看到的代码与实际编译的代码不同。

这是一个关于源代码在某些上下文中如何渲染的问题,其分配的标识符是 CVE-2021-42574。 尽管问题本身不是 rustc 的一个缺陷,但我们正在采取积极措施来减轻其对 Rust 开发人员的影响。

概述

Unicode 支持从左到右和从右到左的语言,为了辅助在从右到左的句子中书写从左到右的词(反之亦然),它还包含称为“双向覆盖”的不可见码点。

这些码点通常在互联网上用于在另一种语言(文本方向不同)的句子中嵌入词语,但有人向我们报告说,它们可能被用于操纵源代码在某些编辑器和代码审查工具中的显示方式,从而导致审查时看到的代码与实际编译的代码不同。如果整个团队依赖于支持双向文本的工具,这将尤其糟糕。

举例来说,以下代码片段(其中 {U+NNNN} 已替换为 Unicode 码点 NNNN

if access_level != "user{U+202E} {U+2066}// Check if admin{U+2069} {U+2066}" {

...在支持双向文本的工具中将被渲染为:

if access_level != "user" { // Check if admin

受影响的版本

Rust 1.56.1 引入了两个新的 lint(代码检查规则)来检测并拒绝包含受影响码点的代码。 Rust 1.0.0 到 Rust 1.56.0 不包含此类 lint,如果您不进行带外检查以确认这些码点是否存在,您的源代码就会容易受到此攻击。

为了评估生态系统的安全性,我们分析了 crates.io 上发布过的所有 crate 版本(截至 2021-10-17),发现只有 5 个 crate 的源代码中包含受影响的码点,且这些出现都不是恶意的。

缓解措施

我们将于今天(2021年11月1日)发布 Rust 1.56.1,其中包含两个新的默认拒绝(deny-by-default)lint,分别用于检测字符串字面量和注释中的受影响码点。这些 lint 将阻止包含这些码点的源代码文件被编译,从而保护您免受攻击。

如果您的代码合法使用了这些码点,我们建议将它们替换为相关的转义序列。错误消息会提示使用正确的转义序列。

如果您无法升级编译器版本,或者您的代码库还包含非 Rust 源代码文件,我们建议您定期检查您的仓库和依赖项中是否存在以下码点:U+202A, U+202B, U+202C, U+202D, U+202E, U+2066, U+2067, U+2068, U+2069。

事件时间线

  • 2021-07-25:我们收到了报告并开始着手修复。
  • 2021-09-14:解除禁令的日期(2021-11-01)通知了我们。
  • 2021-10-17:分析了 crates.io 上发布过的所有源代码,以检查是否存在此攻击。
  • 2021-11-01:禁令解除,漏洞被披露,Rust 1.56.1 发布。

致谢

感谢剑桥大学的 Nicholas Boucher 和 Ross Anderson 根据我们的安全政策向我们披露此问题!

我们还要感谢为解决此问题贡献缓解措施的 Rust 项目成员。感谢 Esteban Küber 开发了这些 lint,Pietro Albini 领导了安全响应,以及许多其他参与、提供见解和反馈的人员:Josh Stone, Josh Triplett, Manish Goregaokar, Mara Bos, Mark Rousskov, Niko Matsakis, and Steve Klabnik。

附录:同形字攻击

作为他们研究的一部分,Nicholas Boucher 和 Ross Anderson 还发现了另一个类似的安全问题,其标识符为 CVE-2021-42694,该问题涉及标识符中的同形字。 Rust 自 1.53.0 版本起已包含针对此攻击的缓解措施。 Rust 1.0.0 到 Rust 1.52.1 版本不受影响,因为这些版本不支持非 ASCII 标识符。