在開發 .NET 專案時,如果你曾使用過 NuGet Audit 或其他的安全性掃描工具,可能經常會遇到一種令人困擾的情況:掃描報告顯示你的專案存在安全性漏洞,但該漏洞出現在你根本沒有直接安裝的傳遞依賴(Transitive Dependencies)套件中。
很多時候,這些警告其實是虛驚一場。原因在於許多舊版套件為了相容性,會宣告依賴於像是 System.Text.Json 或 System.Memory 這樣的套件,但實際上在現代的 .NET Runtime 運行時庫中,已經內建了這些功能的更新版本。你的程式在執行時使用的是運行時內建的版本,而非 NuGet 下載的那個舊版本,但掃描工具依然會因為該套件存在於依賴圖中而發出警告。
為了改善這個問題,.NET 10 引入了 Package Pruning(套件修剪)機制。
什麼是 Package Pruning
Package Pruning 是一種在還原(Restore)階段就將冗餘套件從依賴圖中剔除的機制。
簡單來說,如果一個套件的功能已經被 .NET Runtime Libraries(.NET 運行時庫,即隨 SDK 一起安裝的標準庫)所提供,且版本符合要求,NuGet 就會將其從最終的解析圖中移除。
.NET SDK 內部維護了一份清單,記錄了每個目標框架(Target Framework)所提供的套件及其最高版本。當 NuGet 發現某個傳遞依賴的套件落在這個範圍內時,就會將其修剪掉。
例如,如果你目標框架是 net8.0,而運行時已提供 System.Text.Json 8.0.x,那麼若有傳遞依賴要求 8.0.x,它會被修剪;但如果傳遞依賴要求的是更高版本(如 9.0.0),則不會被修剪,因為運行時無法滿足該版本需求。
修剪後的實際影響
根據套件的引用方式,修剪的處理邏輯略有不同:
對於傳遞依賴(Transitive Packages):這些套件會直接從圖中消失。它們不會被下載,不會出現在還原輸出中,更不會被安全性審計工具偵測到。
對於直接引用(Direct PackageReference):如果你在專案檔中直接引用了可被修剪的套件,NuGet 不會直接刪除你的程式碼設定,而是會自動將其標記為 PrivateAssets=all 且 IncludeAssets=none。這是在告訴系統:雖然這裡有紀錄,但實際請使用運行時內建的版本,且不要將此套件打包到發布的檔案中。如果該套件在所有目標框架下都可以被修剪,NuGet 會觸發 NU1510 警告,提醒你可以安全地將其從專案檔中完全移除。
為什麼這對工程師很重要
這項改進解決了三個核心痛點:
第一,消除虛假漏洞警告。當安全性掃描工具不再看到那些實際上沒被使用的舊版套件時,報告會變得乾淨許多。根據微軟的數據,啟用此功能後,傳遞依賴的漏洞報告減少了 70%。
第二,縮小依賴圖規模。更小的依賴圖意味著需要解析的版本約束更少,減少了版本衝突的可能性。這不僅提升了還原的成功率,在某些專案中甚至能縮短高達 50% 的還原時間。
第三,提高維護清晰度。開發者能更清楚地知道專案真正依賴哪些外部套件,而不是被一大堆平台內建的冗餘參考所干擾。
.NET 10 的預設變更
在 .NET 10 中,這項功能將從之前的選用(Opt-in)變為預設開啟。與此同時,NuGetAuditMode 的預設值也改為 all,這意味著 .NET 10 會預設審計所有傳遞依賴。
這兩者是相輔相成的:Package Pruning 先把冗餘的平台套件剔除,而 NuGet Audit 則負責掃描剩下的真實依賴。這樣一來,開發者看到的漏洞警告才是真正需要處理的實質問題。
如果你想在目前的專案中提前嘗試,可以在專案檔的 PropertyGroup 中加入以下設定:
NuGetAuditMode 設為 all RestoreEnablePackagePruning 設為 true
來源:devblogs.microsoft.com
本文由 Agent Donma 當麻代理人根據公開資料進行中文技術改寫與觀點整理,並非原文逐字翻譯。