檔案上傳是 Web 應用程式中的常見功能,可讓使用者共用圖像、文件或影片等檔案。然而,如果處理不當,文件上傳會帶來安全風險。上傳處理不當可能會導致遠端程式碼執行、覆蓋關鍵檔案和拒絕服務攻擊等漏洞。
為了減輕這些風險,在 PHP 中處理文件上傳時實施安全實務至關重要。以下是有關在 PHP 中安全處理文件上傳的綜合指南,涵蓋最佳實踐、常見漏洞以及保護文件上傳安全的技術。
在 PHP 中,檔案上傳是透過 $_FILES 超全局來處理的,它儲存有關上傳檔案的資訊。以下是文件上傳工作原理的基本範例:
// HTML form for file upload <form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="file" name="fileToUpload"> <pre class="brush:php;toolbar:false">// PHP script to handle file upload (upload.php) if (isset($_POST['submit'])) { $targetDir = "uploads/"; $targetFile = $targetDir . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $fileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION)); // Check if the file already exists if (file_exists($targetFile)) { echo "Sorry, file already exists."; $uploadOk = 0; } // Check file size (limit to 5MB) if ($_FILES["fileToUpload"]["size"] > 5000000) { echo "Sorry, your file is too large."; $uploadOk = 0; } // Check file type (allow only certain types) if ($fileType != "jpg" && $fileType != "png" && $fileType != "jpeg") { echo "Sorry, only JPG, JPEG, and PNG files are allowed."; $uploadOk = 0; } // Check if upload was successful if ($uploadOk == 0) { echo "Sorry, your file was not uploaded."; } else { if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) { echo "The file ". htmlspecialchars(basename($_FILES["fileToUpload"]["name"])). " has been uploaded."; } else { echo "Sorry, there was an error uploading your file."; } } }
始終根據檔案副檔名和 MIME 類型驗證檔案類型。但是,永遠不要只依賴檔案副檔名,因為它們很容易被欺騙。
// Get the file's MIME type $finfo = finfo_open(FILEINFO_MIME_TYPE); $fileMimeType = finfo_file($finfo, $_FILES["fileToUpload"]["tmp_name"]); // Check against allowed MIME types $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($fileMimeType, $allowedMimeTypes)) { die("Invalid file type. Only JPEG, PNG, and GIF are allowed."); }
限制允許的最大檔案大小,以防止可能耗盡伺服器資源的大上傳。您可以透過 php.ini 中的 PHP 設定來執行此操作:
upload_max_filesize = 2M // Limit upload size to 2MB post_max_size = 3M // Ensure post data size can accommodate the upload
此外,使用 $_FILES['file']['size'] 檢查伺服器端的檔案大小:
if ($_FILES["fileToUpload"]["size"] > 5000000) { // 5MB die("File is too large. Max allowed size is 5MB."); }
避免使用原始檔案名,因為它可能被操縱或與其他檔案衝突。相反,將檔案重新命名為唯一識別碼(例如,使用隨機字串或 uniqid())。
// HTML form for file upload <form action="upload.php" method="POST" enctype="multipart/form-data"> <input type="file" name="fileToUpload"> <pre class="brush:php;toolbar:false">// PHP script to handle file upload (upload.php) if (isset($_POST['submit'])) { $targetDir = "uploads/"; $targetFile = $targetDir . basename($_FILES["fileToUpload"]["name"]); $uploadOk = 1; $fileType = strtolower(pathinfo($targetFile, PATHINFO_EXTENSION)); // Check if the file already exists if (file_exists($targetFile)) { echo "Sorry, file already exists."; $uploadOk = 0; } // Check file size (limit to 5MB) if ($_FILES["fileToUpload"]["size"] > 5000000) { echo "Sorry, your file is too large."; $uploadOk = 0; } // Check file type (allow only certain types) if ($fileType != "jpg" && $fileType != "png" && $fileType != "jpeg") { echo "Sorry, only JPG, JPEG, and PNG files are allowed."; $uploadOk = 0; } // Check if upload was successful if ($uploadOk == 0) { echo "Sorry, your file was not uploaded."; } else { if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $targetFile)) { echo "The file ". htmlspecialchars(basename($_FILES["fileToUpload"]["name"])). " has been uploaded."; } else { echo "Sorry, there was an error uploading your file."; } } }
為了防止執行上傳的檔案(例如惡意 PHP 腳本),請將上傳的檔案儲存在 Web 根目錄之外或不允許執行的資料夾中。
例如,將檔案儲存在 uploads/ 這樣的目錄中,並確保伺服器設定不允許 PHP 檔案在該目錄中執行。
// Get the file's MIME type $finfo = finfo_open(FILEINFO_MIME_TYPE); $fileMimeType = finfo_file($finfo, $_FILES["fileToUpload"]["tmp_name"]); // Check against allowed MIME types $allowedMimeTypes = ['image/jpeg', 'image/png', 'image/gif']; if (!in_array($fileMimeType, $allowedMimeTypes)) { die("Invalid file type. Only JPEG, PNG, and GIF are allowed."); }
使用檔案檢查技術,例如驗證映像檔的標頭或使用 getimagesize() 等函式庫來確保檔案確實是映像,而不是偽裝的 PHP 檔案。
upload_max_filesize = 2M // Limit upload size to 2MB post_max_size = 3M // Ensure post data size can accommodate the upload
確保上傳的檔案具有正確的權限且不可執行。設定限制性文件權限以防止未經授權的存取。
if ($_FILES["fileToUpload"]["size"] > 5000000) { // 5MB die("File is too large. Max allowed size is 5MB."); }
首先將檔案儲存在暫存目錄中,只有在執行額外檢查(例如病毒掃描)後才將它們移至最終目的地。
$targetFile = $targetDir . uniqid() . '.' . $fileType;
為了提高安全性,請考慮使用防毒掃描程式來檢查上傳的檔案是否有已知的惡意軟體簽章。許多 Web 應用程式與 ClamAV 等服務整合以進行掃描。
以下是透過整合一些最佳實踐來安全處理文件上傳的範例:
# For Nginx, configure the server to block PHP execution in the upload folder: location ~ ^/uploads/ { location ~ \.php$ { deny all; } }
在 PHP 中安全處理文件上傳需要結合使用技術和最佳實踐來降低惡意文件上傳、大文件上傳和覆蓋重要文件等風險。始終驗證文件類型和大小、重新命名上傳的文件、將其儲存在 Web 根目錄之外,並實施適當的權限。透過這樣做,您可以確保文件上傳功能的安全性並降低被利用的風險。
以上是PHP 中安全文件上傳的最佳實務:防止常見漏洞的詳細內容。更多資訊請關注PHP中文網其他相關文章!