LWN:記錄審計 cargo 中的依賴

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 許可協議。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/grFTFjwP0coXksibGp3b0A