創建和使用 insecure temporary file 會容易使應用程序和系統數據受到攻擊。
應用程序會非常頻繁地使用臨時文件,因此您可以使用多種不同的機制在 C 庫和 Windows(R) API 中創建臨時文件。而多數函數都很容易受到各種攻擊。
示例:以下代碼使用一個臨時文件,在它被處理之前用來存儲從網絡上收集到的中間數據。
...
if (tmpnam_r(filename)){
FILE* tmp = fopen(filename,"wb+");
while((recv(sock,recvbuf,DATA_SIZE, 0) > 0)&&(amt!=0))
amt = fwrite(recvbuf,1,DATA_SIZE,tmp);
}
...
tmpnam()、tempnam() 和 mktemp() 等 C 庫函數以及 C++ 中以 _(下劃線)開頭的相應函數和 Windows API 中的 GetTempFileName() 函數。這組函數在文件名的選擇方面很可能會在底層碰到 race condition。雖然函數可以保證在選擇文件時其文件名是唯一的,但是還無法防止其他進程或攻擊者在選擇文件后,而應用程序尚未嘗試打開該文件前的這段時間內創建一個同名文件。不止是由其他程序調用相同函數所引發的合法沖突,攻擊者還非常有可能創建一個惡意的沖突,因為這些函數創建的文件名沒有進行充分的隨機化,使其難以被攻擊者猜測。 open() 函數并使用 O_CREAT 和 O_EXCL 標記,或者調用 CreateFile() 函數并使用 CREATE_NEW 屬性來打開文件,這樣,如果文件已經存在,創建就會失敗,因此可以有效地防止如上所述的攻擊類型。然而,如果攻擊者可以準確預測一系列臨時文件名,那么可能會阻止應用程序打開必需的臨時存儲空間,導致 denial of service(DoS) 攻擊。如果僅從一小部分隨機數中選擇由這些函數生成的文件名,那么會很容易發動這種類型的攻擊。 tmpfile() 這樣的 C 庫函數和與之對應的以 _ (下劃線) 開頭的 C++ 函數,以及表現更為出色的 C 庫函數 mkstemp()。tmpfile() 類型的函數構造了一個唯一的文件名,并且如果通過了 "wb+" 標記,就能使用與 fopen() 函數相同的方法(即二進制文件的讀/寫模式)打開文件。如果文件已存在,tmpfile() 將把文件的大小縮小為 0,也許能緩解前面提到的安全問題(唯一文件名的選擇與隨后打開所選文件之間的 race condition)。然而,該操作顯然不能解決函數的安全性問題。首先,攻擊者可以預先創建一個能輕松獲取訪問權限的文件,該文件可能會被用 tmpfile() 函數打開的文件保留。其次,在基于 Unix 的系統上,如果攻擊者預先創建了一個文件作為另一重要文件的鏈接,應用程序可能會使用提高了的權限去截短該文件,這樣就能按照攻擊者的意愿執行破壞。最后,如果 tmpfile() 創建了一個新文件,那么應用在該文件上的訪問權限在不同的操作系統間是不同的,因此,應用程序的數據極易受到攻擊,即便是攻擊者無法預測要使用的文件名。 mkstemp() 函數是一種創建臨時文件的安全方法。它根據用戶提供的模板(該模板由一系列隨機生成的字符組成),嘗試創建或打開一個唯一的文件。如果它無法創建一個這樣的文件,則操作失敗,并返回 -1。在最新的系統中,文件使用 0600 模式打開,這就意味著文件不會被篡改,除非用戶直接更改其訪問權限。然而,mkstemp() 仍然會受到使用可預測文件名的威脅,且如果攻擊者通過猜測和預先創建將要使用的文件名的文件,而導致 mkstemp() 函數失效,將使應用程序極易受到 denial of service 攻擊。
[1] .NET System.Security.Cryptography:Random Number Generation Microsoft
[2] BeeCrypt
[3] Crypt++
[4] CryptLib
[5] CryptoAPI:CryptGenRandom() Microsoft
[6] Standards Mapping - Common Weakness Enumeration - (CWE) CWE ID 377
[7] OpenSSL
[8] RtlGenRandom() Microsoft
[9] B. Schneier Yarrow:A secure pseudorandom number generator