供應鏈攻擊
一個軟體供應鏈由用於建立和維護軟體產品的所有軟體和工具組成。這不僅包括為產品本身開發的軟體,還包括其生產過程中使用的所有軟體和工具。
在供應鏈攻擊中,攻擊者針對產品供應鏈的一部分,以危及產品本身。
最明顯的例子是第三方庫。如果你使用,例如,一個由第三方開發的 npm 包,它有能力危及你的網站。它可能故意這樣做,如果它是惡意的,或者意外地,如果它包含其自身的無意漏洞。本質上,你必須像信任自己的程式碼一樣信任你的第三方依賴項。
不太明顯的是,同樣的原則適用於你在建立軟體時使用的所有工具,包括程式碼編輯器、編輯器外掛、版本控制系統、構建工具等等。這些工具中的任何一個都可能在它們應用的轉換過程中,將惡意或易受攻擊的程式碼插入到你的最終軟體產品中。
在本文件中,我們將概述確保軟體供應鏈安全的實踐。它分為兩個主要部分
保護你的開發環境
供應鏈攻擊的一種途徑是攻擊者直接將漏洞或惡意程式碼引入你自己的產品中。本節將介紹一些可以應對此威脅的實踐。
實施訪問控制
對專案中的每個人實施強有力的訪問控制,包括對程式碼倉庫具有寫入許可權或有權修改構建或測試配置的任何人。這裡的好做法包括
保護工具
評估你在網站生產中使用的任何工具的安全風險,包括
- 文字編輯器和 IDE
- 編輯器外掛
- 原始碼控制系統
- 所有參與你的構建、測試和部署過程的工具
對於開源軟體依賴項,你可以使用 OpenSSF 釋出的評估開源軟體的簡明指南作為指導。
保護你的配置
瞭解並應用你的工具的安全設定,尤其是你的原始碼控制系統。關鍵保護措施有
- 確保拉取請求 (PR) 在合併之前經過程式碼所有者的審查和明確批准。
- 確保 PR 在合併之前透過持續整合檢查。
- 要求提交的程式碼是已簽名的。
請參閱 OpenSSF 的原始碼管理平臺配置最佳實踐,其中包括 GitHub 和 GitLab 的具體清單。
管理第三方依賴項
第三方依賴項不僅包括你的程式碼使用的庫和框架,還包括開發過程中涉及的所有第三方工具,如編輯器、IDE、原始碼控制系統、包管理器和構建工具。
為了緩解第三方依賴項帶來的問題,我們將討論四種實踐
- 評估新依賴項
- 更新現有依賴項
- 維護一份 軟體物料清單 (SBOM)
- 對外部指令碼使用子資源完整性
評估新依賴項
在新增新的依賴項之前,你應該評估它代表了多少安全風險。你需要確信該依賴項得到積極維護,它有修復問題的記錄,並有報告和響應安全漏洞的流程。
你應該考慮新增依賴項的風險是否大於自己實現該功能的成本。
由 OpenSSF 釋出的評估開源軟體的簡明指南列出了你在新增新依賴項之前應該提出的問題。
更新依賴項
一旦你將依賴項新增到你的專案中,依賴項的供應商通常會發布帶有新功能、錯誤修復和安全修復的新版本。你通常會希望利用這些更新,透過實現一種機制來保持依賴項的最新狀態。像 GitHub 的 dependabot 這樣的工具可以幫助解決這個問題,它透過檢測新版本的依賴項並自動開啟拉取請求來更新你的專案。
然而,過於急切地更新依賴項也伴隨著其自身的風險。例如,假設你添加了一個對可信第三方包的依賴項。然後攻擊者獲得了包開發者的賬戶控制權,併發布了一個惡意更新。如果你立即接受了更新,你的專案就會受到威脅。
使用鎖定檔案
確保依賴項更新安全的第一步是為依賴項使用鎖定檔案,將其提交到原始碼管理,並在構建專案時使用它。
像 npm 和 Yarn 這樣的包管理器允許你提供一個檔案,比如 package.json,它列出了你專案的依賴項。然後你可以執行一個命令來安裝給定的依賴項,以便專案可以使用它們。
然而,依賴項列表並沒有確定每個包的確切版本:如果包供應商釋出了新版本,那麼它可能會在你的專案構建時自動包含在內。如果依賴項的新版本是惡意的,它可能會在你不自知的情況下自動包含在你的專案中。
例如,假設你的 package.json 包含一個名為“example-dependency”的依賴項
{
"name": "example-project",
"version": "1.0.0",
"dependencies": {
"example-dependency": "^1.0.2"
}
}
假設你的專案構建過程在供應商釋出新版本時自動執行。構建過程透過呼叫 npm install 來啟動構建。這將根據版本範圍 "^1.0.2" 獲取“example-dependency”的最新版本。
在版本 1.0.2(也就是你將其新增到專案的時間點),“example-dependency”是一個有用的、無害的包。然後攻擊者接管了“example-dependency”開發者的賬戶,併發布了一個惡意的 1.0.3 版本。你的構建過程執行,安裝了惡意包,然後你的專案就受到了攻擊。
所有這些都發生在你的專案直接構件沒有任何變化的情況下,也沒有任何機會讓你審查更新並檢視它是否看起來可疑。
解決此問題的方法是在構建專案時使用鎖定檔案。鎖定檔案在專案依賴項安裝時自動生成,它列出了專案中使用的直接和間接依賴項的精確版本。
也就是說,如果 package.json 告訴你你的專案正在使用“example-dependency”,那麼 package.lock 將告訴你確切使用哪個版本的“example-dependency”,以及其依賴項的版本是什麼。
專案的鎖定檔案應被檢入到版本控制中。在構建專案時,應使用鎖定檔案來控制安裝的依賴項版本:在 npm 中,你透過使用 npm ci 而不是 npm install 來實現此操作。
注意:以這種方式固定依賴項的版本有時被稱為“版本鎖定”。
這意味著要更新依賴項,你的構建系統必須發起一個拉取請求來更新鎖定檔案,這給你一個機會來審查更新並確保你想要接受它。
審查更新
在審查依賴項的更新時,考慮這是否是你想要接受的更新
- 閱讀釋出日誌,瞭解它聲稱提供什麼(以及此時你是否需要完全接受它)。
- 檢視它是否引入了任何額外的依賴項。
- 如果可能,審查原始碼更新,看看是否有任何更新是無法解釋的或與更改日誌不符。
- 考慮等待一段時間再更新:通常,供應鏈攻擊很快就會被安全研究人員發現,如果更新在您接受之前被發現是惡意的,那麼對您更有利。
維護軟體物料清單
為了更深入地瞭解您的依賴項,您可以維護一份詳細的依賴項清單。這被稱為 軟體物料清單 (SBOM)。
鎖定檔案實際上是一種 SBOM:但是,“SBOM”一詞通常指用於表示依賴項的獨立標準格式。這些標準通常比鎖定檔案更廣泛和更深入。也就是說
- 它們可以捕獲鎖定檔案中未表示的依賴項,例如 Web 服務。
- 它們可以捕獲每個依賴項的附加資訊,而這些資訊未在鎖定檔案中表示。
使用標準格式表示 SBOM 也意味著你可以
- 與第三方共享您的 SBOM
- 整合能夠理解您的 SBOM 的工具,用於法規遵從或漏洞監控等目的。
表示軟體物料清單的兩種最常見的標準是
這兩個標準都得到了很好的支援,您可以使用其中任何一個來表示您的專案 SBOM。SPDX 最初專注於幫助產品確保符合開源軟體許可證,但已添加了支援安全用例的功能。CycloneDX 是一個較新且更輕量級的標準,從一開始就專注於促進供應鏈安全。
SBOM 的構成
注意:在本節中,我們將使用 CycloneDX 作為 SBOM 格式的具體示例。
本節僅對 CycloneDX 物件模型中最基本的部分進行簡要介紹。有關完整詳情,請參閱 CycloneDX SBOM 權威指南。
在 CycloneDX 中,所有依賴項都是元件或服務。
- 元件包括但不限於軟體框架、庫、應用程式和配置資料。
- 服務代表軟體可能透過端點 URI 等方式呼叫的外部 API。
產品中直接或間接使用的每個元件和服務都由 SBOM 中的一個物件表示。該物件包含有關專案的資訊,包括其名稱、版本、作者、許可證、描述、雜湊值(對於元件)和端點 URI(對於服務)。
SBOM 還列出了產品依賴項中已識別的漏洞。列表中的每個專案都包含有關此漏洞的資訊,包括描述、一組 CWE 程式碼、緩解措施、諮詢連結以及受漏洞影響的元件或服務的識別符號。
建立 SBOM
您可以使用單獨的工具(如 cdxgen)或命令(如 npm sbom)為產品生成 SBOM。SBOM 通常作為構建過程的一部分生成,儘管也可以在軟體生命週期的其他階段生成。
使用 SBOM
SBOM 使您能夠實施多項針對供應鏈攻擊的防禦措施,我們在此列出三項重要的措施
- 漏洞管理:SBOM 的主要用途之一是響應已在您的依賴項中識別的漏洞。您可以使用第三方工具,例如 OWASP 的 Dependency-Track,該工具透過掃描漏洞報告來源(如 NIST 國家漏洞資料庫或 GitHub 諮詢)來自動化此過程。
- 完整性驗證:如果 SBOM 包含依賴項的雜湊值,則可以驗證您所依賴的元件的來源是否未從其原始釋出形式進行修改。
- 供應商風險管理:透過捕獲有關依賴項供應商的資訊,SBOM 可以幫助您瞭解何時依賴來自不再被認為是可靠的供應商的元件或服務。
使用子資源完整性
許多網站都包含外部託管指令碼:最值得注意的是,但不限於,從內容分發網路(CDN)提供的指令碼
<script src="https://cdn.example.org/library.js"></script>
這給你的供應鏈帶來了風險:如果攻擊者能控制 cdn.example.org 域名,他們就能用惡意指令碼替換原有指令碼,從而危及你的網站。
外部指令碼,像其他軟體依賴項一樣,應該成為你的 SBOM 的一部分,但一個額外的防禦措施是設定指令碼的 integrity 屬性
<script
src="https://cdn.example.org/library.js"></script>
此屬性的值包含指令碼內容的加密雜湊。如果指令碼被攻擊者修改,瀏覽器將拒絕載入它,您將受到保護。
這確實增加了額外的維護負擔:每次原始檔更改(例如,每次釋出新版本)時,您都必須更新程式碼中屬性的值。
<link> 元素也支援 integrity 屬性,因此您也可以(並且應該)將其用於 CSS 樣式表以及指令碼。
有關更多詳細資訊,請參閱子資源完整性。