文件上传MIME类型校验,绕过上传漏洞防御

文件上传功能如果只依赖前端或简单的MIME类型校验,很容易被绕过并上传恶意脚本。
本文从零基础视角出发,讲清MIME校验的绕过原理,并给出Nginx、PHP环境下的防御配置和验证步骤,帮你堵住上传漏洞。

绕过是怎么发生的

很多网站只检查浏览器提交的 Content-Type,比如只允许 image/jpeg。
攻击者用Burp Suite等工具抓包,把 Content-Type 改成 image/jpeg,文件内容却是PHP代码,服务器若只信这个头就会放行。

另一种常见绕过是修改文件扩展名,
比如上传 shell.php.jpg,
如果后端只检查扩展名后缀,
可能被解析成PHP。结论:
仅靠客户端或单一MIME头校验无法防御上传漏洞,
必须在服务端做多重校验。

防御配置:Nginx与PHP配合

1. 限制上传目录执行权限

在Nginx站点配置中,找到上传目录的 location 块,添加以下内容禁止执行PHP:

location ~* /uploads/.*\.(php|php5|phtml|jsp|asp|aspx)$ {
    deny all;
}

如果上传目录不需要执行任何脚本,可以直接关闭PHP解析:

location ^~ /uploads/ {
    location ~ \.php$ {
        deny all;
    }
}

修改后执行 nginx -t 测试配置,然后 systemctl reload nginx 重载。

2. PHP端严格校验MIME和扩展名

在接收上传的PHP脚本中,不要只用 $_FILES['file']['type'],而要用 finfo_file() 读取真实MIME:

$finfo = finfo_open(FILEINFO_MIME_TYPE);
$realMime = finfo_file($finfo, $_FILES['file']['tmp_name']);
finfo_close($finfo);

$allowMime = ['image/jpeg', 'image/png', 'image/gif'];
$allowExt  = ['jpg', 'jpeg', 'png', 'gif'];
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION));

if (!in_array($realMime, $allowMime) || !in_array($ext, $allowExt)) {
    exit('文件类型不允许');
}

关键点:finfo_file() 读取文件内容判断类型,比浏览器提交的MIME可靠得多。

3. 重命名上传文件

保存时用随机文件名加白名单扩展名,避免用户控制路径和文件名:

$newName = bin2hex(random_bytes(16)) . '.' . $ext;
move_uploaded_file($_FILES['file']['tmp_name'], '/var/www/uploads/' . $newName);

避坑指南

  • 不要相信 $_FILES['file']['type']:这个值来自客户端,可随意伪造。
  • 不要只检查扩展名:攻击者可能上传 .php.jpg 或利用解析漏洞。
  • 上传目录不要给执行权限:即使文件被上传,也无法运行。
  • 宝塔面板用户:在“网站”->“设置”->“配置文件”中修改Nginx规则,或在“PHP设置”中禁用危险函数如 system、exec。
  • 验证时用真实攻击测试:上传一个内容为 但MIME为 image/jpeg 的文件,确认被拦截。

验证防御是否生效

  1. 用浏览器正常上传一张JPG图片,应成功。
  2. 用Burp Suite抓包,把 Content-Type 改为 image/jpeg,文件内容改为PHP代码,上传应返回“文件类型不允许”。
  3. 直接访问上传目录下的PHP文件,应返回403或404。
  4. 检查Nginx错误日志 tail -f /var/log/nginx/error.log,确认拦截记录。

如果以上步骤都通过,说明MIME类型校验和绕过防御已基本到位。

常见疑问

问:用了 finfo_file() 就绝对安全吗?
答:不是。还需配合白名单扩展名、重命名、目录权限控制和Web应用防火墙。

问:Nginx deny all 会影响图片访问吗?
答:只拦截指定脚本扩展名,图片等静态文件不受影响。

问:宝塔面板如何快速禁用上传目录PHP执行?
答:在网站设置->配置文件里,在 location ~ \.php$ 前添加 location ^~ /uploads/ { deny all; } 并重载Nginx。

防御文件上传漏洞没有一劳永逸的方法,但做好MIME类型校验、扩展名白名单、目录权限隔离这三层,就能挡住绝大多数绕过手段。
建议先在测试环境验证,再应用到生产服务器。

分享到:
上一篇
PHP session存储Redis
下一篇
SQL注入盲注原理,网站防护手段讲解
1
系统公告

泽御云中秋国庆双节活动上线:新购8折,拼团3.99元起

尊敬的用户:
泽御云“月满中秋·礼贺国庆”双节活动现已开启,活动时间为2026年9月23日至10月10日。 活动期间可享以下福利:
1. 常规云服务器新购使用优惠码“泽御中秋国庆同乐”,符合条件的订单享8折优惠。
2. 香港精品云服务器5人拼团低至3.99元,部分4核4G套餐3人拼团年付388元,续费同价。
3. 新用户购买年付云服务器,符合活动规则可赠送2个月使用时长。
4. 老用户续费季度赠15天,续费年度赠2个月;活动期间升级配置免收配置迁移手续费。
5. 推荐好友成功下单,符合条件的推荐人可获赠7天服务器使用时长。
6. 活动期间享宕机补偿标准翻倍、简单网站迁移协助及技术工单优先处理权益。
温馨提示:优惠码不适用于拼团套餐、活动轻量产品、年付订单及续费订单;拼团套餐为独立特价活动,不与赠时类福利叠加。赠送时长不可折现、退款或跨账户转移,具体规则以活动页面说明为准。
服务中心
客服
在线客服
24小时为您服务
咨询
联系我们
联系我们,为您的业务提供专属服务。
24/7 技术支持
如果您遇到寻求进一步的帮助,请过工单与我们进行联系。
24/7 即时支持
泽御云
售前客服
泽御云
泽御云
售后客服
泽御云
技术支持
评价
您对当前页面的整体感受是否满意?
😞
非常不满意
😕
不满意
😐
一般
🙂
满意
😊
非常满意