这是对 官方安全公告 的略微修改后的交叉发布。官方公告还包含使用我们的 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 Boucher 和 Ross 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 自 Rust 1.53.0 起已包含针对该攻击的缓解措施。由于在这些版本中不支持非 ASCII 标识符,因此 Rust 1.0.0 到 Rust 1.52.1 不受影响。