根本原因在于业务代码未同步修复,如eval()、动态类实例化、SQL拼接等高危写法仍存在,且配置错误(如debug开启、数据库文件可访问)持续暴露风险。

ThinkPHP框架升级修复后仍被攻击,根本原因不在框架本身,而在于业务代码没跟着改。
框架层漏洞(比如CVE-2018-20062)靠升级能堵住,但开发者自己写的代码里埋的雷——比如用eval()处理用户输入、拼接SQL、直接调用system()或call_user_func_array()——这些不会因为框架更新自动消失。攻击者绕过已修复的入口,转头就打你Controller里那行eval($_GET['callback'])。
业务代码里的高危写法还在运行
很多项目升级了ThinkPHP版本,但以下写法依然常见:
-
eval('return '.$_GET['code'].';')—— 用户控制整个执行逻辑 -
$class = $_GET['class']; new $class();—— 动态类名实例化 -
Db::query("SELECT * FROM user WHERE id = ".$_GET['id']);—— 原生SQL拼接 -
call_user_func_array($_GET['func'], $_GET['params']);—— 参数全由前端传入
这些不是框架问题,是业务逻辑主动“开门揖盗”。
立即学习“PHP免费学习笔记(深入)”;
配置和习惯性疏忽持续暴露风险
即使代码没问题,下面这些配置错误也会让安全形同虚设:
- 生产环境开着
app_debug = true,泄露路径、数据库结构、变量值 - 数据库配置文件
database.php放在Web可访问目录下,直接暴露账号密码 - 路由未开启严格模式,允许任意控制器/方法被调用(如
s=/index/\think\app/invokefunction) - 上传功能没校验后缀、MIME、内容,导致
safe.php被写成一句话木马
WAF和扫描器对业务层注入基本无效
框架层RCE有固定特征(如invokefunction、?s=),WAF规则好写;但业务层注入千人千面:
-
?action=report&year=2024&tpl=profit_chart→ 后端可能用include $tpl.'.php' -
?callback=userLoginSuccess→ 后端可能call_user_func($callback) -
?rule[status]=exp&rule[value]=1=1 union select password from admin→ 模型where条件被绕过
这类参数语义完全由业务定义,通用规则无法覆盖,必须人工审计每一处动态执行点。
安全加固不能只靠“升级”
真正有效的做法是:
- 全项目搜索
eval、create_function、call_user_func、$$、system、exec、shell_exec,逐个确认参数是否可信 - 所有数据库操作强制走查询构造器或预处理绑定,禁用
Db::query()裸用 - 用户输入一律通过
input()过滤,例如input('get.id', 0, 'intval')或input('post.content', '', 'htmlspecialchars') - 配置文件移出Web根目录,
.env权限设为600,禁止通过URL直接访问任何配置路径 - 关闭
display_errors,关闭allow_url_include,open_basedir限制运行范围
框架修好了只是起点,业务代码才是防守主战场。



















