ThinkPHP上传漏洞需框架层与运行时双线加固:升级至6.x LTS版本,强制启用exts白名单校验,禁用$_FILES直读,关闭上传目录PHP解析,并过滤模板中{php}标签。

ThinkPHP上传漏洞不是靠“加个判断”就能堵住的,核心在于默认配置放行了危险路径、未启用扩展名白名单校验、且模板/路由层未做前置拦截。2026年主流攻击已绕过strstr(strtolower($uploadFile['name']), ".php")这类简单检测,必须从框架层+运行时双线加固。
确认是否还在用 ThinkPHP 3.x 或 5.0–5.1
这些版本的\Think\Upload类根本没实现exts白名单校验逻辑,allowExts只是摆设;而5.2+才真正把$upload->exts = ['jpg', 'png']作为强制过滤项。如果你的composer.json里写着"topthink/framework": "5.1.*",升级是唯一出路。
- 执行
php think version确认当前版本 - 若输出含
v3.2或v5.1,立刻执行composer update topthink/framework:^6.1(6.x 是当前 LTS) - 升级后检查
config/upload.php是否存在,若无则手动创建,确保含'exts' => ['jpg', 'jpeg', 'png', 'gif']
禁用$_FILES直读 + 强制走框架上传器
很多老代码直接用$_FILES['file']['name']做字符串判断,这等于把文件名解析权交给了 PHP 自带的multipart/form-data解析器,而它不校验扩展名、不剥离空字节、不处理大小写混淆。必须让所有上传都经过think\File实例化流程。
- 删除所有类似
if (strstr(strtolower($_FILES['file']['name']), '.php'))的手动判断 - 改用
$file = request()->file('file');获取think\File对象 - 调用
$file->validate(['ext' => ['jpg', 'png']]),该方法会触发真实 MIME 探测 + 扩展名双重校验 - 若验证失败,
$file->getError()返回明确错误,不要用die或return false硬终止
关掉public/Uploads/目录的 PHP 解析能力
即使上传校验通过,攻击者仍可能上传shell.jpg配合 Nginx/Apache 的解析漏洞执行代码。最稳妥的方式是让 Web 服务器彻底拒绝在上传目录执行 PHP。
- Nginx:在对应
location块中添加location ~ \.(php|php5|phtml|php7|php8)$ { deny all; } - Apache:在
public/Uploads/.htaccess中写入Deny from all,并确保AllowOverride All已启用 - 额外保险:将
rootPath设为非 Web 可访问路径,如/data/uploads/,再用控制器生成带签名的临时 URL 返回给前端
别漏掉模板层的{php}标签残留
上传后的图片可能被插入到富文本或模板变量中,如果模板引擎仍允许{php}...{/php}语法,攻击者上传含该标签的 HTML 文件就能触发服务端执行——这和上传 PHP 文件效果等同。
- 检查
config/template.php中'type'是否为'think'(非'default') - 确认
'tpl_replace_string'已配置['{php}' => '{notag}', '{/php}' => '{/notag}'] - 若项目用了自定义模板解析器,务必在
view_filter行为中对所有输出内容做str_replace(['{php}', '{/php}'], '', $content)
真正难堵的是“合法文件+非法上下文”的组合,比如上传一个看似正常的 SVG 文件,但它内部含<script>fetch('/api/user')</script>,再被模板直接echo $content渲染——这种漏洞不会报错,但会悄悄泄露数据。上传安全从来不是单点问题,它卡在框架配置、Web 服务器、模板引擎、甚至前端富文本编辑器之间。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











