Go 官方部落格了他們應對供應鏈攻擊的緩解措施。據稱,Go 的工具鏈和設計在各個階段均包含降低攻擊風險的考慮。
所有構建都被「鎖定 (locked)」
外部變化(例如釋出依賴項的新版本)不會影響 Go 構建。
與其他大多數軟體包管理器所使用的組態檔不同,Go modules 沒有單獨的約束列表和用於鎖定特定版本的 lock 檔案。參與 Go 構建的每個依賴項的版本完全由主模組的
從 Go 1.16 開始,上述操作預設執行,如果不完整,構建命令將失敗。唯一會改變go.mod
的命令是 go get
和 go mod tidy
。這些命令通常不會自動執行或在 CI 中執行,因此這種對依賴關係樹的改變通常都是刻意為之,可在程式碼審查階段被發現。
這對於安全性非常重要,如果一個模組被入侵併行布了一個新的惡意版本,那麼在明確更新該依賴項之前,任何人都不會受到影響,從而為生態提供了審查更改和檢測事件的時間。
版本內容永不改變
確保第三方不會影響構建的另一個關鍵屬性是,module 版本的內容不可改變。因為如果破壞依賴項的攻擊者可以重新上傳現有版本,他們就可以自動破壞所有依賴該依賴項的專案。
這正是go.sum
檔案的用途。它包含有助於構建的每個依賴項的加密雜湊列表。同樣,不完整的go.sum
會導致錯誤,並且只能使用go get
和go mod tidy
對它進行修改。因此,對它的任何修改都會伴隨著主觀的依賴關係改變。
VCS 是事實來源
大多數專案在開發過程中都會使用版本控制系統 (VCS),在其他生態中,這些專案還需要上傳到中心軟體包倉庫 (比如 npm)。這意味著有兩個帳戶可能會受到破壞,即 VCS 主機和中心軟體包倉庫。後者使用得更少,也更容易被忽視。這也意味著更容易在上傳到倉庫的版本中隱藏惡意程式碼,特別是如果原始碼作為上傳的一部分被例行修改。
Go 沒有諸如中心軟體包倉庫帳戶這類東西。包的匯入路徑嵌入了直接從 VCSgo mod download
獲取其模組所需的資訊,其中 VSC 上的標籤定義了 module 版本。
僅構建程式碼,但不執行
Go 工具鏈有一個明確的安全設計目標:無論是獲取還是構建程式碼,都不會讓該程式碼執行,無論程式碼是否不受信任或者惡意。
這是一種有意義的風險緩解措施,假如你正在執行一個二進位制檔案或測試一個只使用一個子集的包模組的依賴。例如,如果example.com/cmd/devtoolx
在 macOS 上構建和執行,那麼針對 Windows 的依賴或example.com/cmd/othertool
的依賴就不可能危害到你的機器。
在 Go 中,不為特定構建提供程式碼的 module 對於構建沒有安全影響。
「複製勝於依賴」
最後一項(也可能是最重要)供應鏈攻擊風險緩解措施也是技術含量最低的:Go 有拒絕大型依賴樹的文化,並且更喜歡複製而不是新增新的依賴。
這可以追溯到 Go 的一句諺語:(複製勝於依賴)。
Go module 對自己的「零依賴」標籤非常自豪。如果開發者需要使用一個庫,他會發現這個庫不會讓他依賴其他作者和所有者的幾十個 module。
這意味著只需少量依賴項就可以構建豐富、複雜的應用程式。畢竟無論工具多好,它都無法消除重用程式碼所涉及的風險,因此最強的緩解措施始終是只有一個小的依賴樹。