3 回答

TA貢獻1898條經驗 獲得超8個贊
在處理 $_FILES['file'] 之前我需要過濾它嗎?
簡短的回答:不。它只是一堆字符串值,僅此而已。
長答案:
我曾經通過檢查文件類型及其擴展名來了解這些文件是否在白名單中來保護網絡應用程序。
如果正確應用和執行,這是一個很好的方法。
$_FILES 數組只是一個載體。它本身不能被濫用,但您必須信任它所攜帶的內容 - 即信任正在傳遞給服務器/由服務器傳遞的文件。
當我寫這個答案時;以下;?OP 似乎對他們實際上要防范的內容及其原因感到困惑:
OP 聲明為“最佳實踐”(這絕對不是):
如果您想使用 $_FILES['file']['tmp_name'] 存儲到數據庫中或顯示在 UI 中,您應該使用 addslashes 或 PDO 準備語句來防止 SQL 注入攻擊。
$_FILES
這是對數組填充方式的誤解。該值由服務器$_FILES['file']['tmp_name']
設置,而不是由用戶或客戶端設置。
用戶給定的值為:
$_FILES['file']['name'] $_FILES['file']['type'] $_FILES['file']['size']
這些是需要審查的字符串值。只要您不信任這些字符串值,就無需擔心。
在數據庫中存儲文件通常不是一個好主意,并且有其自身的陷阱, dhnwebpro對于這個問題(關于數據庫安全)
$_FILES['file']['tmp_name']
是文件在臨時存儲空間中的服務器位置。
PHP手冊明確指出:
默認情況下,文件將存儲在服務器的默認臨時目錄中,除非在 php.ini 中使用 upload_tmp_dir 指令指定了另一個位置??梢酝ㄟ^在 PHP 運行環境中設置環境變量 TMPDIR 來更改服務器的默認目錄。
如果該文件尚未被移走或重命名,則該文件將在請求結束時從臨時目錄中刪除。
如果您認為您的$_FILES['file']['tmp_name']
價值被濫用,那么這是服務器受到損害的跡象,您的盤子里會遇到一大堆麻煩,遠遠超出了惡意文件上傳的范圍。
那么,如何審核正在攜帶的文件呢?
文件攻擊有多種類型,這個主題遠遠超出了您所詢問的范圍。例如;?真正的 JPEG 圖像可以在 JPEG 元數據中包含 XSS 腳本,但在加載和查看 JPEG 時會觸發此 XSS,但出于所有意圖和目的,JPEG 文件不是“壞文件”或不是 XSS 文件,以不專門檢查此漏洞的外部觀察者。
那么,您是阻止此文件file.jpg
還是阻止所有Jpeg 文件?這是一個艱難的決定,但在 PHP 中,有一些非常好的解決方法(我認為這也超出了這個問題的范圍)。簡而言之;?您的問題可以進行一些編輯并澄清您到底想要防止什么以及您愿意在多大程度上達到該保護級別。
我可以為您提供一個粗略的包羅萬象的指南,以防止某些MIME 文件類型被您的服務器接受。這看起來和感覺就像你想要的,可以阻止偷偷摸摸的 MP4 視頻作為文檔文件上傳(反之亦然)。
1:
忽略文件名 (?$_FILES['file']['name']
)。永遠不要相信用戶數據。
您可能需要保留原始文件名,在這種情況下,您應該使用 REGEX 或類似的命令檢查它以刪除不需要的字符...
2:
忽略聲明的文件類型 (?$_FILES['file']['type']
)。任何給定 MIME 類型的文件名(例如.pdf
)都應該被忽略。永遠不要相信用戶數據。
3:
使用PHPFinfo
函數集作為初步指標。它并不完美,但可以捕獲大多數東西。
$finfo = finfo_open(FILEINFO_MIME_TYPE); // return mime type ala mimetype extension
$mimeType = finfo_file($finfo, $_FILES['file']['tmp_name']);
$whitelist = ['text/html','image/gif','application/vnd.ms-excel'];
finfo_close($finfo);
if(in_array($mimeType,$whitelist)){
? ? // File type is acceptable.
}
4:圖片:
finfo
如果您要檢查上傳的圖像,最好的方法是按照3檢查文件類型,然后讓 PHP 將圖像加載到空白畫布中并重新保存圖像,從而刪除所有多余的元數據和其他可能不需要的非圖像數據-數據。
像這樣的方法:使用 php 從 jpg 中刪除 exif 數據。
5:
還建議始終為上傳的文件提供隨機名稱,切勿使用該$_FILES['file']['name']
值。
6:
根據您試圖避免和/或消除的威脅類型,您可以打開上傳的文件并讀取文件的前幾個字節,并將其與該類型白名單文件中的已確認字節進行比較。這是非常微妙的,并且再次超出了這個答案的范圍,這個答案已經足夠長了。

TA貢獻1829條經驗 獲得超4個贊
有一個函數is_uploaded_file可以確定該文件確實是上傳的文件,而不是用戶進行的某種文件路徑操作。據我所知,沒有辦法is_uploaded_file($_FILES['file']['tmp_name'])
會返回 false。您還應該檢查是否filesize($_FILES['file']['tmp_name'])
小于您要插入的列的大小。
至于“直接存儲到數據庫”,你仍然需要對文件內容進行良好的SQL注入防護。此外,通常很難擴展將文件存儲在數據庫中的解決方案,但這是一個您可能已經考慮過的單獨問題。

TA貢獻1801條經驗 獲得超8個贊
如果您使用 PDO 或 MySQLi,您應該能夠將文件放在準備好的語句中,這應該可以保護您免受 SQL 注入攻擊。我粘貼了https://www.mysqltutorial.org/php-mysql-blob/中的方法,其中有一些有關在 MySQL 數據庫中存儲文件的好信息。
/**
?* insert blob into the files table
?* @param string $filePath
?* @param string $mime mimetype
?* @return bool
?*/
public function insertBlob($filePath, $mime) {
? ? $blob = fopen($filePath, 'rb');
? ? $sql = "INSERT INTO files(mime,data) VALUES(:mime,:data)";
? ? $stmt = $this->pdo->prepare($sql);
? ? $stmt->bindParam(':mime', $mime);
? ? $stmt->bindParam(':data', $blob, PDO::PARAM_LOB);
? ? return $stmt->execute();
}
或者,您可以將文件存儲在文件系統上,并在需要提供文件時僅包含對該文件的引用。此方法速度更快,但不方便將所有數據保存在一處。
有關數組元素的詳細信息$_FILES有點隱藏在手冊中,但可以在示例 1 的末尾找到:
https://www.php.net/manual/en/features.file-upload.post-method.php
數組所有元素的值$_FILES應視為用戶輸入。我建議忽略這些值。但是,如果您希望將它們寫入數據庫和/或稍后在 UI 中顯示它們,那么您肯定需要保護自己免受 SQL 注入和 XSS 攻擊。因此,在這種情況下,使用準備好的語句htmlspecialchars不會有什么壞處。
- 3 回答
- 0 關注
- 151 瀏覽
添加回答
舉報