攻擊者可以通過將惡意腳本(如PHP 代碼)偽裝成圖片上傳。例如,將一個包含PHP 後門的腳本命名為.jpg或.png ,然後上傳。若不使用exif_imagetype()檢測實際文件類型, image_type_to_extension()可能會錯誤地返回合法擴展名,從而誤導後續邏輯,甚至將其保存在可執行目錄中:
$filename = $_FILES['image']['tmp_name'];
$ext = image_type_to_extension(@exif_imagetype($filename));
// 錯誤用法:沒有檢測exif_imagetype返回值是否為false
$newName = uniqid() . $ext;
move_uploaded_file($filename, "/var/www/html/uploads/" . $newName);
如果上傳的文件並非真實圖片,例如一個偽造的PHP 腳本,但擴展名是.jpg ,攻擊者就可能通過訪問http://m66.net/uploads/xxxx.jpg執行惡意代碼。
當exif_imagetype()不能識別文件類型時,它會返回false 。如果此時仍將結果傳入image_type_to_extension() ,會返回.int(0) ,導致生成文件名混亂,甚至邏輯異常。例如:
$type = exif_imagetype($filename);
$ext = image_type_to_extension($type);
// 如果$type為false,$ext為"."
這樣可能會導致程序使用錯誤的文件擴展名,影響後續操作,甚至造成資源洩露。
在某些服務器環境中,如果PHP 沒有啟用fileinfo或exif擴展,那麼exif_imagetype()會失效。若仍然依賴其結果並傳入image_type_to_extension() ,程序容易崩潰或處理邏輯錯誤,影響用戶體驗。
有些服務部署安全策略是基於擴展名進行限制,比如只允許.jpg 、 .png文件被訪問。如果攻擊者偽造文件名,並繞過後端檢查,服務器可能錯誤地授予訪問權限。
例如,上傳了一個名為.php.jpg的文件,但真實格式是PHP。 Nginx 在某些配置下會將其識別為.php文件而執行,從而產生嚴重後果:
<?php echo shell_exec($_GET['cmd']); ?>
然後通過訪問:
http://m66.net/uploads/backdoor.php.jpg?cmd=ls
即可遠程控制服務器。
為了避免上述風險,應該採取以下措施:
使用exif_imagetype()且判斷返回值是否為false
使用finfo_file()來進一步驗證MIME 類型
限制上傳目錄不可執行
不信任用戶提交的擴展名
使用白名單驗證image_type_to_extension()的返回值
示例代碼:
$filename = $_FILES['image']['tmp_name'];
$imageType = @exif_imagetype($filename);
if ($imageType === false) {
die('不支持的圖片格式');
}
$ext = image_type_to_extension($imageType, false);
$allowed = ['jpg', 'jpeg', 'png', 'gif'];
if (!in_array($ext, $allowed)) {
die('不允許的圖片類型');
}
$newName = uniqid() . '.' . $ext;
move_uploaded_file($filename, '/var/www/uploads/' . $newName);