如何通過語言提供的能力來防範Log4j之類的漏洞?

banq發表於2021-12-27

功能能力安全(capability-safe)的語言(如Rust)可以最大限度地減少甚至防止Log4j漏洞發生。

在本文中討論圍繞Log4j漏洞的兩個問題:

  1. 它會對使用者提供的字串進行字串插值。
  2. 它會訪問網路,而沒有人意識到它可能會這樣做。(這是能力安全的語言可以提供幫助的部分。)

。。。

log4j維護人員考慮實施引入導致漏洞的 JNDI 功能時,接下來可能會發生一些事情:

  1. 他們認為日誌庫在預設情況下始終訪問網路是完全合理的,並Network 為該Logger.getLogger()方法新增了一個引數。一些使用者接受了這一點併成為該漏洞的犧牲品,但更挑剔的使用者擔心此網路訪問請求並切換到不需要它的更簡單的其他日誌記錄庫,從而避免了該漏洞。
  2. 他們認為日誌庫根本不應該訪問網路,或者認為需要一個Network引數會讓使用者感到害怕或不方便,因此拒絕了該功能。
  3. 他們認為該功能能力是值得的,但不希望修改的破壞性 API 更改getLogger需要Network. 因此,他們引入了一種新方法,可能稱為 Logger.getLoggerWithNetwork(MyClass.class, network). 由於大多數使用者不使用這種方法並且log4j沒有它就無法訪問網路,因此可以防止絕大多數漏洞。

這三種可能性都比實際發生的情況要好,實際情況是:log4j突然獲得了訪問網路的能力,但其 API 並未更改以反映這一點,因此使用者沒有注意到

因此,功能安全的語言本可以節省或至少減輕這一點。

所以未來的語言設計師,請考慮讓你的語言功能能力安全。

 

Rust基於能力的安全

作業系統有一個資源控制程式碼或檔案描述符的概念,它們是可以在程式內部和有時在程式之間傳遞的值,代表對外部資源的訪問。程式通常具有 環境許可權,只需提供其名稱或地址即可請求任何檔案或網路控制程式碼:

let file = File::open("/anything/you/want.txt")?;

可能有訪問控制列表、名稱空間、防火牆或虛擬化機制來管理哪些資源可以實際訪問,但這些通常是粗粒度的,並在應用程式之外進行配置。

基於能力的安全尋求避免環境權威,使沙箱更細粒度和可組合。要開啟檔案,需要一個Dir,代表它所在的開啟目錄:

let file = dir.open("the/thing.txt")?;

嘗試訪問未包含在目錄中的路徑:

let hidden = dir.open("../hidden.txt")?;

dir.symlink("/hidden.txt", "misdirection.txt")?;
let secret = dir.open("misdirection.txt")?;

返回PermissionDenied錯誤。

這允許應用程式邏輯配置自己的訪問,而無需更改整個主機程式的行為、設定單獨的主機程式或需要外部配置。

 

cap-std是Rust 標準庫的基於能力的版本,cap-std專案圍繞同名的cap-stdcrate 進行組織,並開發了一些庫以簡化基於功能能力的程式碼的編寫,包括:

Cap-std 具有針對CWE-22 的保護功能,即“對受限目錄的路徑名的不當限制(‘路徑遍歷’)”,它在2021 年 CWE 前 25 名最危險的軟體弱點中排名第 8 。它還可用於防止不受信任的輸入誘導程式在 Linux 上開啟“/proc/self/mem”。

 

相關文章