核心问题是校验位置与文件后续处理脱节;需同步加固服务端真实内容检测(如finfo_file、getimagesize)、上传目录禁执行、随机重命名及多层校验。

PHP上传白名单绕过漏洞的核心问题,不是白名单本身写得不够严,而是校验逻辑与文件实际落地、解析、执行之间存在脱节。只靠扩展名白名单,等于在门口查身份证,却不管人进屋后干了什么。修复必须从“校验位置”和“后续处理”两个维度同步加固。
别只信文件名和Content-Type
攻击者能轻易伪造$_FILES['file']['name']和HTTP请求里的Content-Type字段,前端JS校验、后端仅检查扩展名或MIME类型,基本形同虚设。
- 禁用客户端JavaScript校验(如禁用浏览器JS)可直接绕过前端限制
- 用Burp Suite抓包修改
Content-Type: image/png即可骗过仅依赖MIME的后端判断 - 双后缀(
shell.php.jpg)、大小写混淆(SHELL.PHP)、空格点截断(shell.php.)都能让白名单校验失准
必须做服务端真实内容检测
文件“叫什么”不重要,关键看它“是什么”。要用PHP原生函数读取文件二进制头(魔术字节),确认内容与声称类型一致。
- 图片类文件:用
getimagesize()或finfo_file()验证是否真为PNG/JPG/GIF - 通用检测:
finfo_open(FILEINFO_MIME_TYPE)获取真实MIME,比$_FILES['type']可靠得多 - 对非图片类白名单(如
.zip),应解压后递归检测内部文件,防止嵌套恶意脚本
切断文件被执行的路径
即使恶意文件侥幸上传成功,只要它无法被Web服务器解析执行,风险就大幅降低。
- 上传目录禁止配置PHP解析:Apache中用
<directory></directory>禁用php_flag engine off;Nginx中用location ~ ^/upload/.*\.(php|php5|phtml)$ { deny all; } - 存储时强制重命名:用
uniqid().mt_rand()生成随机名,彻底丢弃原始$_FILES['name'] - 禁止解析.htaccess/.user.ini:上传目录设置
AllowOverride None,并过滤这些特殊配置文件名
警惕时间差与解析机制漏洞
某些老版本PHP(%00截断,或因先保存再校验导致竞态条件(上传后未删前被快速访问),这类底层机制问题必须规避。
- 升级PHP至当前稳定版(8.1+),默认已修复
%00截断等历史缺陷 - 校验必须在
move_uploaded_file()之前完成,且校验失败立即unlink($_FILES['tmp_name']) - 避免将用户可控参数(如
save_path)拼接到文件路径中,杜绝路径遍历与截断可能
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











