必须用 finfo_open() 校验真实 mime 类型,严格白名单过滤,重命名时彻底弃用原始文件名并清洗,上传目录须脱离 web 路径,配合禁用危险函数,且所有校验须在 move_uploaded_file() 前完成。

只靠检查 $_FILES['file']['type'] 或后缀名,根本防不住上传木马——它连第一道门都拦不住。
用 finfo_open() 校验真实 MIME 类型
客户端传来的 $_FILES['file']['type'] 和文件扩展名全可伪造,攻击者把一句话木马改成 shell.jpg 就能绕过绝大多数前端+简单后端判断。必须读文件头。
- 用
finfo_open(FILEINFO_MIME_TYPE)打开文件流,调finfo_file()获取真实类型,例如返回"image/jpeg"或"application/x-php" - 白名单必须严格限定:只允许
"image/jpeg"、"image/png"、"application/pdf"这类无执行能力的类型;明确拒绝"text/html"、"application/x-php"、"application/x-sh" - 注意:
finfo在 PHP 5.3+ 默认启用,但某些精简容器镜像可能未编译,需确认extension= fileinfo已在php.ini中启用
重命名时强制剥离原始文件名与路径
不丢弃 $_FILES['file']['name'],就等于给攻击者留了 ../etc/passwd、.htaccess、shell.php.jpg 的入口。
- 完全忽略用户提交的文件名,不用
pathinfo($name, PATHINFO_EXTENSION)提取后缀 - 生成新名:用
uniqid('up_')+bin2hex(random_bytes(8))+ 映射后的固定扩展名(如image/gif → '.gif') - 确保新名不含
/、\、空格、控制字符;用preg_replace('/[^a-zA-Z0-9._-]/', '', $new_name)清洗一次更稳妥
上传目录必须脱离 Web 可访问路径
即使文件名安全、类型干净,只要放在 /var/www/html/uploads/ 这类目录下,攻击者一旦绕过某次校验,就能直接 GET 到 webshell。
- 把上传目录设在 Web 根目录外,例如
/var/data/uploads/,并通过 PHP 脚本代理访问(如download.php?id=abc123) - 若必须放 Web 目录内,至少加
.htaccess(Apache)或location ~ \.php$ { deny all; }(Nginx)禁用脚本解析 - 确认该目录权限为
755,文件为644,绝不可777——很多木马正是靠写入同目录下的.user.ini或php.ini绕过限制
配合 disable_functions 收紧运行时能力
就算木马文件落地,没有 system、exec、eval 等函数,它也只剩“哑巴”。这是最后一道运行时防线。
- 在
php.ini中设置disable_functions = exec,passthru,shell_exec,system,proc_open,popen,eval,assert,base64_decode,gzinflate - 注意:
eval和assert是动态代码执行核心,base64_decode和gzinflate常被用于解密载荷,必须禁用 - 禁用后部分合法组件(如某些模板引擎、调试工具)可能异常,上线前务必在测试环境验证
最易被忽略的是:所有校验必须在 move_uploaded_file() 之前完成。一旦文件已落盘,再删再拒都晚了——攻击者可能已在并发请求中触发了那个刚写入的 shell。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











