ThinkPHP本身无独立“文件删除漏洞”CVE,但业务中路径拼接未校验、扩展名白名单缺失、缓存清理逻辑失控三类写法易导致任意文件删除;防御需禁用动态路径拼接、路径标准化锁定根目录、删除前强制权限校验与日志记录。

ThinkPHP本身不直接存在“文件删除漏洞”这个独立CVE编号漏洞,但实际攻防中,文件删除行为常被滥用为攻击链一环——它不是框架原生功能缺陷,而是开发者在业务逻辑中不当调用文件操作函数(如 unlink、rmdir、File::delete()),配合用户可控路径参数,导致任意文件删除,进而引发配置泄露、WebShell残留、甚至服务瘫痪。
漏洞成因:三类典型危险写法
以下代码模式在老项目或快速开发中高频出现,极易触发越权删除:
-
路径拼接未校验:接收用户传入的
file=../config/database.php,直接拼进unlink($root . $_GET['file']),绕过目录限制 -
扩展名白名单缺失:仅判断
pathinfo($file, PATHINFO_EXTENSION) === 'jpg',却忽略xxx.jpg/.php这类双重扩展或空字节截断 -
缓存/日志清理逻辑失控:如
public function clearCache() { array_map('unlink', glob(ROOT_PATH . 'runtime/cache/*.php'));,若该方法未做权限校验且路由可被未授权访问,攻击者可构造恶意s=Index/clearCache批量删关键缓存甚至误删其他目录
防御要点:从输入到执行全程设防
防御核心是不信任任何用户输入,不放行任何未经强约束的文件路径操作:
- 禁用动态路径拼接:改用预定义键值映射。例如删除头像时,只允许
type=avatar&id=123,后端查数据库得真实路径upload/avatar/123_20260817.jpg,再执行删除 - 路径标准化+根目录锁定:对用户传入路径先用
realpath()解析,再用strpos($realpath, ROOT_PATH) === 0确保不跳出项目根目录;ThinkPHP 6+ 可配合think\File的validatePath()方法自动拦截非法路径 - 删除前强制二次确认:涉及敏感目录(如
runtime/、config/、public/upload/)的操作,必须校验当前用户角色权限,并记录操作日志(含IP、时间、目标路径)
应急响应:发现异常删除后的处置动作
若日志中已出现大量 unlink(): No such file or directory 或监控告警 runtime 目录突变为空,立即执行:
立即学习“PHP免费学习笔记(深入)”;
- 暂停所有含
unlink、rmdir、File::delete的控制器方法,临时返回 403 - 检查
runtime/log/下最近 2 小时的 error.log,定位被调用的控制器与参数来源 - 扫描项目中所有
unlink(、rmdir(、File::delete(出现位置,重点审查是否缺少is_file()/is_dir()判断及路径白名单 - 恢复被删文件:从最近一次 Git 提交或备份中还原
config/、app/等核心目录;若 runtime 被清空,重启服务即可自动生成,无需人工干预
文件删除风险不在函数本身,而在上下文控制力。只要路径来源可控、执行边界清晰、操作留痕可溯,就不存在真正意义上的“删除漏洞”。



















