ThinkPHP 8.0.3 的 where() 字段绕过漏洞源于字段名未校验,导致拼接非法字段(如 user_nam)生成无效 SQL 条件而静默执行,可能引发越权或数据泄露;须通过 Db::getFields() 动态白名单、模型 strict+allowField 双重校验及全局中间件参数过滤进行防护。

ThinkPHP 8.0.3 的 where() 查询字段绕过问题,本质是字段名不校验导致的静默失败与逻辑漏洞——写错字段(如 username 写成 user_nam)不会报错,而是生成无效 SQL 条件,可能造成越权、空结果误判或数据泄露。这不是语法错误,而是安全防护缺位。
字段名必须白名单校验,不能依赖 where() 自身
TP8.0.3 的 where() 方法完全不检查字段是否真实存在于数据库表中。它直接拼进 SQL,MySQL 会忽略非法字段名(如 WHERE user_nam = ?),查询仍执行成功但条件失效。攻击者可借此探测字段、绕过业务限制或构造恶意排序/分组。
-
Db::table('user')->where('user_nam', 'test')->select()→ 不报错,返回全量用户 -
UserModel::where(['user_nam' => 'test'])->find()→ 同样静默跳过,等价于无条件查询
在查询前用 Db::getFields() 做动态白名单
对所有用户可控的字段名(如排序字段 sort=user_nam_desc、搜索字段 field=mobile、where 键名),必须在使用前校验:
$allowed = Db::getFields('user'); // 返回 ['id','username','email','mobile','create_time']
$field = input('sort', '');
$cleanField = preg_replace('/_(asc|desc)$/i', '', $field); // 提取基础字段名
if (!in_array($cleanField, $allowed)) {
throw new HttpException(400, '非法字段:' . $cleanField);
}
- ✅ 适用:
order(),group(),where([$key => $val]),field()动态传参 - ⚠️ 注意:
Db::getFields()返回小写字段名,比对前统一转小写;别名、反引号需提前清洗。
模型层开启 strict + allowField 双重锁定
仅靠数据库层校验不够,模型操作也需拦截:
修复 Core bailout 状态损坏安全问题,以及 BZ2、DOM、PDO、Opcache/JIT 内存与执行错误,改进 Unicode 字素处理、URL 解析、TLS 流状态、信号分发及会话错误处理。
$user = new UserModel(); $user->strict(true); // 必须显式开启,否则 allowField 无效 $user->allowField(['id', 'username', 'email', 'mobile']); // 下面这行会直接抛异常:'is_admin' 不在白名单中 $user->where(['username' => 'a', 'is_admin' => 1])->find();
- ✅
strict(true)+allowField()组合后,where()、save()、update()所有键名都会被校验 - ❌ 单独
allowField()不起作用;不设strict(true)就等于没开保护。
生产环境推荐:全局中间件统一拦截
新建 ParamWhitelistMiddleware,在 handle() 中集中处理所有请求参数字段:
public function handle(Request $request, \Closure $next)
{
$params = $request->param();
$allowed = ['id', 'username', 'email', 'mobile', 'status', 'sort', 'page'];
foreach (array_keys($params) as $key) {
// 过滤掉非字段类参数(如 token、page、_t)
if (in_array($key, ['token', 'page', 'limit', '_t'], true)) continue;
if (!in_array($key, $allowed)) {
throw new HttpException(400, '请求参数非法:' . $key);
}
}
return $next($request);
}
- ✅ 覆盖所有控制器入口,避免漏掉某个方法的手动校验
- ✅ 可配合配置中心动态加载白名单,便于多模块差异化管理
不复杂但容易忽略
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!










