thinkphp 8.x 入口改为 think\app 类,路由注册基于注解或 config/route.php 闭包映射,不再依赖 app/route.php 数组;默认启用 pdo 严格预编译,但手动拼接 sql、未校验的文件路径及反序列化调用仍存高危风险。

ThinkPHP8.x的入口和路由机制变了,别再套5/6的审计路径
ThinkPHP8.x彻底重构了应用生命周期和请求调度逻辑,index.php不再直接加载thinkphp/start.php,而是通过 Composer 自动加载入口类 think\App。路由注册也不再依赖 app/route.php 的全局数组绑定,而是基于注解(@route)或独立的 config/route.php 返回闭包/控制器映射。如果你还按 TP5 习惯去翻 app/route.php 找动态路由拼接点,大概率会漏掉真实入口。
实操建议:
- 先确认
config/app.php中'default_route' => true是否关闭——开启时会启用“自动多级控制器”路由,index.php/v1/user/info可能直接映射到app\controller\v1\user\Info::index(),参数未显式声明就极易失控 - 搜索
@route注解和Route::get/post/any调用,重点看闭包路由里是否直接用了$_GET或input()未校验参数 - 检查
app/middleware.php是否注册了自定义中间件——TP8 中间件执行顺序更严格,但若在中间件里调用Request::param()并拼进日志或缓存键,也可能触发二次污染
SQL注入判断不能只看有没有PDO预编译
TP8 默认使用 PDO,并强制开启 PDO::ATTR_EMULATE_PREPARES = false,但这不等于绝对安全。真正危险的是开发者绕过 Query 构建器,手动拼接 SQL 字符串后传给 Db::execute() 或 Connection::query()。
常见错误现象:
- 报错信息里出现
SQLSTATE[42000]且堆栈指向Connection.php的query()方法,而非select()/find() - 代码中存在类似
"SELECT * FROM user WHERE id = " . $id或"IN (" . implode(',', $ids) . ")"的硬拼接 - 使用
whereRaw()时第二个参数没传绑定数组,比如whereRaw('status = ?', [$status])正确,但whereRaw("status = $status")就危险
性能影响:TP8 的查询日志默认开启,log/sql 里会记录完整 SQL——如果拼接了用户输入,敏感字段(如密码哈希、token)可能直接明文落盘。
文件操作类漏洞集中在 Request::file() 和 Input::path()
TP8 把文件上传统一收口到 Request::file(),看似安全,但若后续调用 moveTo() 时目标路径由用户控制(比如从 input('save_path') 拼接),就构成路径穿越。更隐蔽的是 Input::path()——它用于解析 URL 路径段,但默认不校验 ../,配合 file_get_contents() 或 view()->fetch() 就可能触发任意文件读取或模板注入。
使用场景举例:
- 接口接收
GET /api/template?name=../../runtime/log/sql_202610.log,后端用view()->fetch(input('name'))渲染——TP8 允许fetch()加载任意 PHP 文件,只要路径可达 -
Request::file('avatar')->validate(['size'=>2048])->move(UPLOAD_PATH . input('dir')),其中input('dir')未过滤../,导致文件写入非预期目录 - 配置项
'upload' => ['root' => '/var/www/html/uploads']硬编码在config/filesystem.php,但业务代码又用input('base_dir')动态覆盖,形成信任链断裂
反序列化利用面收窄,但 __wakeup 和 __destruct 仍需人工确认
TP8 移除了 think\Model 的 __wakeup() 魔术方法(历史版本曾在此处触发反序列化 gadget),也禁用了 unserialize() 在缓存驱动中的默认使用。但如果你在代码里看到 unserialize($request->cookie('data')) 或 igbinary_unserialize(),就得立刻停住——TP8 不拦截这些原生调用。
容易踩的坑:
- 第三方 SDK 或旧版兼容层(如
think-queue低版本)仍在用serialize()存 job 数据,若 Redis 或数据库被污染,反序列化时可能触发__destruct()中的file_put_contents()或system() - 自定义异常处理器里有
log()->error($e->getTraceAsString()),而$e是用户可控对象,其__toString()可能含危险逻辑 - TP8 的容器支持绑定闭包,但若闭包引用了外部变量(如
function() use ($userInput) { eval($userInput); }),且该闭包被序列化存储,风险依然存在
复杂点在于:TP8 的依赖注入容器和事件系统大量使用反射与动态调用,单靠关键词扫描(如 unserialize)会漏掉间接调用链。必须从可控输入点(如 Cookie、Header)出发,人工追踪每一步对象构造和方法调用。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











