修复PHP缓存泄露漏洞需阻断“用户输入→缓存写入→恶意执行”链:禁止缓存文件被Web解析(.htaccess/Nginx deny规则)、移出Web根目录、过滤换行符等危险字符、禁用原样缓存用户数据、改用安全后缀与分级存储,并实测验证403/404响应。

修复PHP缓存泄露用户数据漏洞,关键在于阻断“用户输入→缓存写入→恶意执行/读取”这条攻击链。这类漏洞多见于ThinkPHP 3.2.x(如S()函数缓存注入)、自定义文件缓存未过滤换行符、或缓存内容直接拼接用户可控数据等场景。不是所有缓存都会泄露,但一旦缓存文件被解析为PHP(如写成.php后缀)或可被Web直接下载(如.cache未屏蔽),风险就极高。
立即清理并阻止缓存文件被解析
攻击者常通过猜解缓存文件名(如md5("name").php)访问并执行恶意代码。必须从服务器层面切断访问路径:
- 在Apache的
.htaccess中添加:
<FilesMatch "\.(php|cache|log|dat)$">
Require all denied
</FilesMatch> - 在Nginx配置中加入:
location ~ \.(php|cache|log|dat)$ {
deny all;
} - 检查
runtime/、Cache/、Temp/等缓存目录是否在Web根目录下;若在,立即将其移出(如放到/home/www/private/cache/),并在代码中用绝对路径加载
修复缓存写入逻辑,过滤危险字符
ThinkPHP 3.2.x经典漏洞源于S()写入时未处理%0A(换行符),导致缓存文件内嵌PHP代码。通用修复思路是净化输入内容:
- 打开缓存驱动文件(如
thinkphp/library/think/cache/driver/File.php),定位set()方法,在序列化或写入前插入:
$value = str_replace(["\r", "\n", PHP_EOL], '', $value); - 若使用自定义缓存类,所有写入前统一调用
strip_tags()+preg_replace('/[^\w\s\.\-\_\[\]\(\)]/', '', $data),只保留安全字符 - 禁用将用户POST/GET参数原样缓存的做法——例如
S('user_input', $_POST['data'])必须改为先校验再缓存
调整缓存配置与存储方式
降低缓存本身的风险等级,比事后堵漏更可靠:
立即学习“PHP免费学习笔记(深入)”;
- 关闭调试模式:确保
APP_DEBUG = false,避免缓存中混入堆栈、SQL等调试信息 - 改用非PHP后缀:在缓存配置中指定
'type' => 'file', 'ext' => '.dat',并配合上一步的deny all规则 - 启用子目录分级:设置
'subdir' => true和'level' => 2,使缓存文件散列到多层目录,大幅增加猜解难度 - 生产环境禁用
file_get_contents($cache_file)类动态包含操作;如必须读取,用fopen($file, 'rb')+ 严格校验文件头
验证是否修复成功
别只改代码,要实测确认漏洞已封死:
- 尝试构造含
%0A的请求触发缓存写入,然后访问对应缓存文件URL,应返回403/404,而非PHP执行结果或明文内容 - 用
curl -I https://yoursite.com/runtime/cache/xxx.php检查响应头是否含HTTP/1.1 403 Forbidden - 查看缓存目录下生成的文件,确认无
<?php、eval(、system(等敏感片段



















