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-01,发布 Rust 1.56.1,其中包含两个新的默认拒绝的 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 BoucherRoss Anderson 根据我们的安全政策向我们披露此事!

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

附录:同形字攻击

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