finfo_file是唯一可信的mime校验方式,因$_files'file'可被伪造、后缀白名单易被shell.php.jpg等绕过;必须在moveto前用finfo_file校验临时文件真实类型,并重命名存至非web可访问目录。

finfo_file 是唯一能信的 MIME 校验方式,仅靠 validate(['ext' => 'jpg,png']) 等同于没校验。
为什么 $_FILES['file']['type'] 和后缀白名单都不可信
浏览器传来的 $_FILES['file']['type'] 是前端自填的字符串,改个 text/plain 就能绕过;validate(['ext' => 'jpg,png']) 只检查文件名后缀,攻击者上传 shell.php.jpg 或 webshell.PHP 就直接穿防。ThinkPHP 5.1 的 FileValidate 类默认不读文件内容,也不调用 finfo,纯靠扩展名做判断。
必须在 moveTo() 前用 finfo_file() 做真实类型校验
校验必须发生在临时文件还存在、且未被移动前。常见错误是先 $file->move() 再去读目标路径——此时临时文件已被删,finfo_file() 会失败或返回空。
-
finfo_open(FILEINFO_MIME_TYPE)必须开启fileinfo扩展(PHP 默认启用,但某些 Docker 镜像可能禁用) - 不要用
getimagesize():对非图像文件会触发警告,且可被构造的 JPEG APPx 段绕过 - 校验逻辑应封装进
callback规则,避免散落在控制器里 - 示例代码:
use think\FileValidate;
$file = request()->file('image');
$validate = new FileValidate();
$result = $validate->rule([
'size' => 'require|between:0,2097152',
'ext' => 'in:jpg,png,gif,jpeg',
'callback' => function($data) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$realType = finfo_file($finfo, $data['tmp_name']);
finfo_close($finfo);
return in_array($realType, ['image/jpeg', 'image/png', 'image/gif']);
}
])->check($_FILES['image']);
if (!$result) {
throw new \Exception('文件类型非法:' . $validate->getError());
}
上传后必须重命名 + 存到非 Web 可访问目录
即使类型校验通过,攻击者仍可能利用 Web 服务器解析漏洞(如 Apache 将 .php.jpg 当 PHP 执行,或 Nginx 的 fastcgi_split_path_info 截断)执行恶意代码。
- 原始文件名必须丢弃,用
uniqid() . '.' . $safeExt生成新名 - 目标路径不能是
public/uploads/这类 Web 可直访目录,应选runtime/upload/或storage/app/uploads/ - 若必须放 public 下,Nginx 配置需加:
location ~ \.(php|phtml|phar)$ { deny all; } - Linux 权限设为
755,且上传目录不属www-data用户,防止写入后直接执行
ThinkPHP 5.1 的 FileValidate 使用陷阱
它只认 $_FILES 数组原始键名,比如 size、extension、tmp_name,不支持点号嵌套(如 file.size)或自定义字段名。
- 多文件上传时,
$_FILES['images']['name'][0]这种结构需先用think\facade\File::parseFiles()转成标准单维数组 -
rule()中的ext规则默认不区分大小写,但 Web 服务器可能区分(如.PHP在某些 Apache 配置下仍可执行),建议手动转小写比对 - 别依赖
type规则:validate(['type' => 'image/jpeg'])实际查的是$_FILES['file']['type'],不是真实 MIME
finfo_file 返回 image/jpeg,只要文件最终落在可执行路径下、且服务器配置松动,一张“图片”就能变成后门。php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











