老代码升级thinkphp后漏洞反复出现,根源在于未清理旧业务中动态方法调用、模板eval、配置拼接、命令行参数直传、会话id明文暴露等危险逻辑;必须先清除挂马文件、切断三条攻击路径、重写五类高危写法。

老代码升级ThinkPHP后漏洞反复出现,不是因为补丁没打全,而是旧业务逻辑里埋着未清理的危险调用链——比如动态方法名、模板eval、配置文件拼接、命令行参数直传、会话ID明文暴露,这些代码在新框架下依然能被利用。
先清入侵残留:定位并删除挂马文件
这一步不做,后续所有加固都白费。攻击者常借漏洞写入隐藏PHP文件,藏在public/、themes/、runtime/甚至vendor/子目录中。
进入项目根目录,执行以下命令快速筛查可疑PHP文件:
find . -name "*.php" -type f -size +5k -size -100k | xargs grep -l "base64_decode|eval|assert|shell_exec|system|passthru|gzinflate|str_rot13" 2>/dev/null
重点检查:【public/static/、themes/default/、runtime/cache/、app/common/behavior/】 这些目录下突然多出的、命名异常(如a.php、1.php、x.php、index1.php)或无git记录的PHP文件,直接删除。
使用D遁webshell工具(v3.1)本地扫描全项目:选中项目根目录→点击“开始扫描”→人工核对高危匹配项(非全部自动删),尤其关注加密后门特征:混淆变量名($OOO000000、$O0O000000)、连续substr+base64_decode嵌套、__destruct中调用不可信对象。
再断执行路径:三步止血法立即生效
升级框架只是基础,必须同步切断攻击者最常走的三条路:调试入口、动态调用入口、危险函数入口。
方法一:关闭所有调试与远程能力
打开config/app.php,确认以下配置已强制设为false且无环境变量覆盖:
'app_debug' => false, 'app_trace' => false, 'remote_debug' => false, 'show_error_msg' => false
然后清空runtime/log/、runtime/cache/、runtime/debug/ 全部内容——【日志文件若不清空,调试关闭形同虚设】。
方法二:拦截核心攻击参数
在public/index.php中define('APP_PATH', ...)之后,插入如下请求过滤代码:
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['_method'])) { $method = strtoupper($_POST['_method']); if (!in_array($method, ['GET','POST','PUT','DELETE','PATCH'])) { http_response_code(403); die('Invalid method'); } } $danger_keys = ['s', 'function', 'vars', 'filter', 'order', 'group', 'having']; foreach (array_merge($_GET, $_POST) as $k => $v) { if (in_array($k, $danger_keys) || (is_string($v) && preg_match('/\\think\\|call_user_func.*array|eval|assert/i', $v))) { http_response_code(403); die('Blocked'); } }
最后挖业务雷区:五个高危写法必须重写
这是漏洞反复出现的根源。框架升级后仍被攻破,90%以上源于以下五类代码未清理:
① 动态类/方法调用 → 改用白名单映射
查找所有call_user_func、call_user_func_array、$obj->$method()、$class::$func()结构,且其中$method、$class、$func来自$_GET、$_POST、路由参数或数据库字段。例如:$action = input('action'); call_user_func($action, $data); 必须改为:$map = ['export' => 'doExport', 'import' => 'doImport']; $real = $map[$action] ?? null; if ($real) { $this->$real($data); }
② 模板/规则字符串执行 → 禁用eval,改用预编译表达式
搜索项目中所有eval(、create_function(、preg_replace('/.*/e',,尤其是邮件模板渲染、后台富文本解析、表单验证规则字段。将动态拼接的PHP代码逻辑,全部替换为Symphony ExpressionLanguage或自定义白名单函数调用(如只允许date()、strtoupper()、md5()等安全函数)。
③ 配置文件动态包含 → 校验+硬编码白名单
定位所有include、require、file_get_contents拼接路径的代码,如include 'config/'.$tenant.'.php'。必须改为:$allowed = ['default', 'cn', 'en']; $tenant = input('tenant') ?: 'default'; if (!in_array($tenant, $allowed)) { throw new HttpException(400, 'Invalid tenant'); } $config = include 'config/' . $tenant . '.php';
④ 命令行脚本参数直传 → 全部加escapeshellarg()
检查所有shell_exec()、exec()、system()、proc_open()调用,凡参数含用户输入(如$_GET['file']、input('cmd')),必须用escapeshellarg()包裹。错误写法:shell_exec('ls ' . input('path')); 正确写法:shell_exec('ls ' . escapeshellarg(input('path'))); 【未加包裹的命令调用,升级框架也无法防御】。
⑤ Cookie/Session 安全缺失 → 强制设置三项属性
在config/session.php中确认:'use_cookies' => true, 'cookie_httponly' => true, 'cookie_secure' => true(HTTPS环境),'cookie_samesite' => 'Lax';同时检查所有setcookie()调用,确保第7个参数为true,且第5个参数(domain)不为空或为通配符。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











