关注了就能看到更多这么棒的文章哦~
Vetting the cargo
By Jonathan Corbet
June 10, 2022
DeepL assisted translation
https://lwn.net/Articles/897435/
现代语言环境使人们很容易发现外界提供的库,并且纳入自己的程序中。这些机制也很可能会让我们无意中引入安全漏洞或公开的恶意代码,这就不是什么开心的事情了。由此产生的漏洞似乎永远不会停歇,这一点在 Rust 这样相对安全的语言中也有相同的困扰。为了避免由于依赖关系来引入漏洞(或更坏的代码)所带来的尴尬,Mozilla 项目想出了一个新的供应链管理工具,称为 "cargo vet"。
The problem
现代的开发环境非常有吸引力。比如一个开发者在开发某个功能时,可能突然发现需要在某个字符串的左侧填充空格来对齐。与其自己痛苦地写代码来实现这个功能,我们的开发者完全可以直接在相应语言的资源库中找到一个合适的 module,把它添加到 project manifest 文件中,然后直接使用就好了。这使得我们的开发者可以利用别人所做的工作,从而完全专注于他们自己的核心任务,毕竟这些更加重要,比如让弹出窗口能不被广告拦截器拦截。。。
这种方法有一个明显问题:我们的开发者对这个新添加的 module 里有哪些内容一无所知,并且对这个 module 可能悄悄引入的其他所依赖 module 一无所知。当 module 第一次被 import 时,情况就是这样,当这些依赖关系在后续有更新时,情况更是如此,这甚至可能是由原作者以外的人所更新的。这是很多潜在安全问题的共同点。
多年来,Mozilla 项目一直试图以各种方式提高 Firefox 浏览器的安全性;其中之一就是用 Rust 语言重写浏览器的大部分代码,毕竟 Rust 语言本身就是 Mozilla 创造的。不过,目前为止,火狐浏览器的大部分代码都来自于项目之外,公告中是这么说的:
火狐的 Rust 集成工作使我们的工程师可以很容易地从 crates.io 中提取现成的代码,而不是从头开始编写。这对生产力来说是件好事,但也增加了我们产品的攻击面(attack surface)。我们的 dependency tree 已经稳步增长到近四百个第三方 crate 了,而我们迄今为止还缺乏一种机制来有效地审计这些代码,并确保我们在系统性地进行这项工作。
近四百个第三方 crate 看起来确实是非常大的攻击面了。其中任何一个错误都可能导致一个脆弱的浏览器被发布,而含有恶意软件的 crate 的后果可能会更严重。该项目正在考虑如何解决这一威胁,这的确是件好事。
Tracking code audits
有很多方法可以提高对某块代码的安全性的信心。用内存安全的语言编写代码就是这样一种方式;在没有 unsafe block 的 Rust 程序中,有很多问题根本不可能会存在。但是,人们需要的不仅仅是这些,最终,没有什么可以替代对代码进行阅读和理解来了解它的作用的工作。如果像 Firefox 这样的程序是由经过严格 review 的代码构建的,那么对其安全性的信心就会更高。
基于 Rust 的 Cargo 依赖管理机制以及构建系统中的 cargo vet 机制,就是希望能帮助完成这项任务。它不能完成实际进行代码 review 这种的复杂繁琐的工作,但它可以帮助跟踪哪些代码已经被 audit,并确保未经 audit 的代码不会进入 production build。
一开始搭建的时候,cargo vet 在源代码目录下创建一个新的目录,叫做 supply-chain;这个新目录包含了几个文件,例如 audits.toml 和 config.toml。此时还会检查项目的所有依赖关系(这些依赖关系原本已经在 cargo.lock 文件中跟踪记录),并将它们全部标记为未经 audit 的。
开发者可以通过在 audits.toml 中增加一个 block,将某个 module 标记为已经完成 audit(应该是要在实际进行了 audit 工作之后),如下所示:
[[audits.left-pad]]
version = "1.0"
who = "Alice TheAuditor <NothingGetsPastMe@example.com>"
criteria = "safe-to-deploy"
这条记录就表明,left-pad crate 的 1.0 版本(而且只有这个版本)完成了 audit,并被认为在生产构建中是 "safe-to-deploy"。cargo vet 里面已经定义了两个 "criteria",另一个就是 "safe-to-run";后续可以根据需要添加其他的。有一些方法可以用来表明某些系列版本已经被 audit 过,或者从一个版本到下一个版本的 patch 已经被 audit 过。也可以对某个范围内的那些版本加入一个 violation 信息;这表明这些版本没有通过 audit,不应该被使用。audits.toml 的更多例子可以在这个页面(https://mozilla.github.io/cargo-vet/recording-audits.html)上找到。
在这些 audit 到位之后,就可以运行 cargo vet 来确保当前 build 中的所有代码都已被审计。如果某些依赖关系被更新过了,该工具将指出它们需要 audit,并阻止构建成功。它还可以从 crates.io(而不是例如 github 等网站上的 project 页面上)来获取相关依赖的源代码,从而确保被审计的代码与所部署的代码是完全相同的。
换句话说,cargo vet 工具可以帮助一个项目来跟踪其依赖关系的 audit 情况,从而帮助将未经审核的代码发布给用户。但是,这并不能改变一个事实,那就是对所有的代码进行 audit 本身就是一项工作量巨大的工作。不过,如果各个 project 可以合作并分享他们所做的 audit,那么这里也有很多工作可能可以被省下来。
Bringing in the community
推动 cargo vet 的另一个关键目标就是希望在社区中扩散 audit 工作。由于某个项目的 audits.toml 文件会是其源码库的一部分,因此它就可以被其他任何能看到该源码库的人使用;对于大多数开源代码来说,这就意味着全世界都可以使用。换句话说,一个项目的 audit 工作的结果通常可以让世界上的其他人看到并加以利用。毕竟,如果一个项目 audit 了某个依赖关系,并且没有发现任何问题,只要这个 project 的判断是值得信任的,那么其他 project 就没有理由再重复这项工作了。
为了利用另一个项目已经完成的 audit 工作,可以让 cargo vet 来导入其 audits.toml 文件,并接受其中的审计结果。不用说,在将自己的审计任务委托给互联网上的其他人之前,应该先要存在一定程度的信任关系。目前还没有什么机制可以查到有哪些 audit 存在了,也没有办法(至少在 cargo vet 中还没有办法)来验证 audits.toml 文件中列出的人是否真的做过审计——任何一个有相应权限的人都可以添加他们想要的任何文本。不过,如果这个机制后续真的流行起来了,那么这样的功能可以在未来添加。
这项工作的总体目标是消除不正确对依赖关系进行审计的借口:
每个新参与者都会自动将其审计结果贡献给公众,使每个人都能逐渐减少自己来检查依赖关系的工作。我们已经多次了解到,推动生态系统向更安全的方向发展的最好方法就是把原本困难的事情变得简单,而这正是我们在这里所做的。
我们希望,随着审计代码数量的增加,cargo vet 的使用量也随之增加。准备好基础设施可能是一个良好开端,但是,正如公告所指出的,还有一个可能难以克服的问题。"没有办法独立验证审计是否被忠实和充分地执行" 了。如果没有某种 reputation 系统让用户决定他们应该真正信任哪些 audit,那么创建一个在整个社区分享 audit 的系统就会是一项艰巨的任务。
不过,这个项目是刚出现不久的,所以存在一些缺失也就不奇怪了。毫无疑问,cargo vet 正试图解决一个迫切的问题,所以很高兴看到这项工作开展起来。如果这个方法得到了证实,那才可以比较放心地使用某个不知名作者在某个中心软件库中随机提供的 module。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
欢迎分享、转载及基于现有协议再创作~
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~