ThinkPHP缓存文件漏洞是多重历史漏洞叠加的共性风险,需从写入、存储、读取、执行四环节同步修复:写入阶段禁止危险字符混入,如用户输入直接写入缓存。

ThinkPHP缓存文件漏洞不是单一问题,而是多个历史漏洞叠加暴露的共性风险:缓存内容未过滤、序列化数据可被污染、缓存文件可被执行。修复不能只清目录或改配置,得从写入、存储、读取、执行四个环节同步堵漏。
缓存写入阶段:禁止危险字符混入
漏洞常始于用户输入直接进缓存,比如 Cache::set('name', input('get.data'))。攻击者传入换行符(%0d%0a)、注释符(//)、PHP标签(<?php )等,就能绕过缓存驱动默认的简单处理,把恶意代码“合法”写进.php缓存文件。
- 所有写入缓存的数据必须先过滤:去除
\r\n、;、phpinfo、eval、assert等敏感字符串 - 避免用
S()或Cache::set()缓存原始POST/GET参数,应先校验类型、长度、正则格式 - 若必须缓存用户输入,建议统一转为JSON格式存储(
json_encode()),而非PHP原生序列化
缓存存储阶段:禁用.php后缀+强制权限隔离
ThinkPHP默认将缓存存为.php文件,一旦路径可被Web直接访问(如runtime/cache/被Nginx误配为可执行),攻击者就能通过URL请求触发webshell执行。
- 修改
config/cache.php,将File驱动的suffix设为'.dat'或'.bin',彻底规避PHP解析 - 确保
runtime/cache/目录在Web根目录外,或Nginx/Apache中明确禁止执行该目录下所有PHP文件:location ~ ^/runtime/cache/.*\.php$ { return 403; } - 设置
runtime/cache/目录权限为750,属主为Web运行用户(如www-data),禁止其他用户写入
缓存读取阶段:校验完整性再反序列化
unserialize()报错(如Error at offset 0 of 4 bytes)表面是文件损坏,深层是反序列化前缺乏校验。损坏文件可能被恶意构造利用,也可能因磁盘异常导致安全机制失效。
立即学习“PHP免费学习笔记(深入)”;
- 重写
think\cache\driver\File::get()方法,在unserialize()前检查文件头是否以'// ThinkPHP Cache'.等可信标识开头 - 对缓存内容增加简单校验码(如MD5前缀),读取时比对,不匹配则跳过并记录告警
- 生产环境禁用
unserialize(),改用json_decode()或igbinary_unserialize()(需扩展支持)
运行时防护:拦截+降权+监控三道防线
即使缓存层有疏漏,也要阻止其演变为RCE。关键不是“能不能写”,而是“写了也执行不了”。
- Nginx层加规则拦截已知攻击特征:
if ($args ~* "(s=|function=|vars\[0\]=)") { return 403; } - PHP配置中禁用高危函数:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,unserialize - 部署文件监控脚本,当
runtime/cache/下出现新.php文件或修改时间异常时,自动告警并临时锁定目录



















