仅靠后缀白名单防御上传漏洞不够,必须服务端硬编码白名单(如jpg、png等)、配合finfo真实MIME校验、重命名文件并禁用上传目录执行权限。

PHP 8.1 中仅靠后缀白名单防御上传漏洞是不够的,但它是基础且必要的第一道防线。关键在于:白名单必须严格、服务端执行、不依赖前端或用户输入,且需配合其他校验手段才能真正起效。
白名单必须用服务端硬编码,不能拼接或动态生成
错误写法:$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)); if (in_array($ext, ['php', 'phtml', 'phar'])) { die('禁止'); }——这是黑名单,且易绕过。
正确做法:只允许明确安全的扩展名,且从固定数组中精确匹配:
-
用小写统一处理:
$ext = strtolower(pathinfo($_FILES['file']['name'], PATHINFO_EXTENSION)); -
白名单硬编码限定范围:如
$allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp']; -
严格全等判断:用
in_array($ext, $allowed, true),避免字符串隐式转换漏洞
后缀白名单只是起点,必须叠加 MIME 类型校验
攻击者可修改请求中的 Content-Type 或构造畸形文件头,单靠后缀无法识别真实内容。PHP 8.1 推荐使用 finfo 扩展做二进制探针:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
- 启用
fileinfo扩展(PHP 8.1 默认已启用) - 用真实文件内容检测类型:
$finfo = new finfo(FILEINFO_MIME_TYPE); $mime = $finfo->file($_FILES['file']['tmp_name']); - 只接受图像类 MIME:
in_array($mime, ['image/jpeg', 'image/png', 'image/gif', 'image/webp'], true)
必须重命名文件,彻底剥离原始后缀
即使通过了白名单和 MIME 校验,仍要防止攻击者利用解析漏洞(如 Nginx 空字节、Apache .htaccess 配置、IIS 双扩展等)。安全做法是:
- 丢弃用户传来的全部文件名,包括原始后缀
- 生成唯一随机名:
$new_name = bin2hex(random_bytes(16)) . '.png'; - 保存时强制指定扩展名,与上传名完全解耦
额外加固点不可省略
在 PHP 8.1 环境下,还需同步配置:
- 上传目录禁止执行脚本:
deny all;(Nginx)或Options -ExecCGI(Apache) - 禁用危险函数(如
eval,assert,system)在生产环境的php.ini中 - 设置
upload_max_filesize和post_max_size合理值,防 DoS - 开启
open_basedir限制脚本访问范围
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










