当前位置: 首页> 最新文章列表> image_type_to_extension() 使用时不检查文件格式会出什么问题?有哪些风险?

image_type_to_extension() 使用时不检查文件格式会出什么问题?有哪些风险?

M66 2025-06-23

不检查文件格式的风险

1. 伪造文件类型绕过上传验证

攻击者可以通过将恶意脚本(如 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 执行恶意代码。

2. exif_imagetype() 失败返回 false,但仍传入 image_type_to_extension()

exif_imagetype() 不能识别文件类型时,它会返回 false。如果此时仍将结果传入 image_type_to_extension(),会返回 .int(0),导致生成文件名混乱,甚至逻辑异常。例如:

$type = exif_imagetype($filename);
$ext = image_type_to_extension($type);
// 如果$type为false,$ext为"."

这样可能会导致程序使用错误的文件扩展名,影响后续操作,甚至造成资源泄露。

3. 未开启 fileinfoexif 扩展

在某些服务器环境中,如果 PHP 没有启用 fileinfoexif 扩展,那么 exif_imagetype() 会失效。若仍然依赖其结果并传入 image_type_to_extension(),程序容易崩溃或处理逻辑错误,影响用户体验。

4. 依赖扩展名的安全策略失效

有些服务部署安全策略是基于扩展名进行限制,比如只允许 .jpg.png 文件被访问。如果攻击者伪造文件名,并绕过后端检查,服务器可能错误地授予访问权限。

例如,上传了一个名为 .php.jpg 的文件,但真实格式是 PHP。Nginx 在某些配置下会将其识别为 .php 文件而执行,从而产生严重后果:

<?php echo shell_exec($_GET['cmd']); ?>

然后通过访问:

http://m66.net/uploads/backdoor.php.jpg?cmd=ls

即可远程控制服务器。


正确的使用方式

为了避免上述风险,应该采取以下措施:

  1. 使用 exif_imagetype() 且判断返回值是否为 false

  2. 使用 finfo_file() 来进一步验证 MIME 类型

  3. 限制上传目录不可执行

  4. 不信任用户提交的扩展名

  5. 使用白名单验证 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);