ThinkPHP 3.2.5非官方稳定版,实际风险仍属3.2.3已知漏洞范畴,加固须关闭DEBUG模式、禁访Runtime/Logs、过滤?s=路由及m/c/a参数、严控数组注入、约束模板加载与缓存写入。

ThinkPHP 3.2.5 并非官方正式发布的稳定版本(官方最新 3.x 版本为 3.2.3),所谓“3.2.5”多为社区非官方修改包或误标版本。实际生产中遇到的代码注入类问题,绝大多数仍归属 ThinkPHP 3.2.3 的已知漏洞范畴,包括 RCE(如 CVE-2018-20062 变种)、EXP 数组注入、模板包含、日志泄露等。修复不依赖“升级到 3.2.5”,而应聚焦真实风险点做精准加固。
关闭调试模式并阻断日志访问
这是所有加固的前提。DEBUG 模式开启时,Runtime/Logs/ 下会生成含 SQL、堆栈、参数的明文日志,攻击者可直接 URL 访问下载(如 /Runtime/Logs/24_10_15.log)。
- 检查 Application/Common/Conf/config.php 或入口同级 Conf/config.php,确保
'APP_DEBUG' => false已生效;全局搜索确认无其他配置覆盖该值 - Nginx 配置中添加:
location ^~ /Runtime/Logs/ { deny all; };Apache 则在 Runtime/Logs/ 下放 .htaccess,内容为Deny from all - 清空现有日志文件,并将 Runtime/ 目录权限设为仅 Web 进程用户(如 www-data)可写,禁止组和其他用户读取
拦截危险路由与参数构造
ThinkPHP 3.2 的 ?s= 路由机制是 RCE 主要入口。不能删路由,但必须过滤非法字符和危险函数名。
- 在 index.php 最顶部插入校验逻辑:
if (isset($_GET['s']) && preg_match('/[\\\/\.\:\:]|invokefunction|call_user_func|eval|assert|system|shell_exec|passthru|exec/i', $_GET['s'])) { die('Access denied'); } - 对传统
m=、c=、a=参数同样限制:只允许字母、下划线,拒绝反斜杠、点号、双冒号、方括号等(例:preg_match('/^[a-zA-Z_]+$/i', $_GET['c']) === false则拒访) - 若使用 URL_REWRITE,需同步检查 .htaccess 或 Nginx rewrite 规则,避免绕过参数过滤
堵死 EXP 注入与数组型 SQL 注入
漏洞核心在于 where()、find() 等方法接受用户输入的数组参数(如 id[0]=exp&id[1]==1 and 1=1),导致 SQL 片段被直接拼接。
立即学习“PHP免费学习笔记(深入)”;
- 禁用裸用
I('get.id')后直传数组——改用带类型强制的写法:I('get.id/d')(转整型)、I('get.name/s')(转字符串并过滤)、I('get.status/d', 0)(设默认值) - 所有涉及
where($map)的地方,避免动态构造array('exp', ...);如确需表达式,改用预处理绑定:where('status = ? AND create_time > ?', array(1, time())) - 在基类模型(如 Application/Common/Model/BaseModel.class.php)的
select()/find()前增加参数白名单校验,拒绝含exp、in、like等关键字的数组键名
约束模板加载与缓存写入
攻击者可通过可控参数触发 fetch() 加载任意路径模板,或利用 S() 缓存写入恶意 PHP 代码。
- 重写视图层
display()或fetch()方法,在解析模板路径前做严格白名单判断,例如只允许./Application/Home/View/下的子路径,禁止../和绝对路径 - 修改 ThinkPHP/Library/Think/Cache/Driver/File.class.php 中的
set()方法,在序列化前清除换行符和 PHP 标签:$value = str_replace([" ", " ", "", "?>"], '', $value); - 避免将用户输入(尤其是 POST 内容)直接传给
S('key', $_POST);如需缓存,先做htmlspecialchars()或 JSON 编码再存



















