thinkphp验证器默认不丢弃多余字段,需显式启用strict模式或使用only()方法过滤;验证通过不代表数据安全,save前必须手动提取合法字段。

ThinkPHP 验证器默认不丢弃多余字段
默认情况下,validate() 方法只校验传入数据是否符合规则,但不会自动过滤掉验证规则里没定义的字段。攻击者只要在表单里多加个 status 或 is_admin 字段,而你的验证规则没显式写它,TP 就照单全收——哪怕模型里有 $this->allowField([]),也拦不住验证器“睁一只眼”。
常见错误现象:Db::name('user')->insert($data) 直接入库,结果数据库被写入了本不该出现的字段;或者用 save() 时意外覆盖了敏感字段。
- 必须显式启用严格模式:在验证器类中设置
protected $failException = true;并配合scene+only控制字段白名单 - 更可靠的做法是:验证通过后,用
array_intersect_key($data, array_flip($validator->getRuleNames()))手动提取合法字段(注意getRuleNames()返回的是规则键名,不是全部字段) - 别依赖模型的
allowField做第一道防线——它在验证之后才起作用,顺序上就晚了
strict 模式不是开关,而是要配 scene + only
strict 参数只在调用 validate() 时生效,且仅对当前验证场景起作用;它本身不自动过滤字段,只是让验证器在遇到未定义字段时报错。但报错 ≠ 过滤,你得自己 catch 后做清理,或者换种方式控制输入边界。
使用场景:API 接口接收 JSON 数据、后台表单提交含隐藏字段、第三方回调带扩展参数。
- 定义验证器时用
protected $scene = ['edit' => ['name', 'email']]明确字段白名单 - 验证时必须写
$validate->scene('edit')->check($data),否则scene不生效 - 调用
check()时传入['strict' => true]第二个参数(TP6.0+),例如:$validate->check($data, [], ['strict' => true]) - TP5.1 不支持该参数,只能靠
only()方法:用$validate->only(['name', 'email'])->check($data)
validate() 和 validateScene() 的字段过滤差异
validate() 是通用入口,不绑定场景,也不自动限制字段;validateScene() 内部会调用 scene(),但依然不自动丢弃多余字段——除非你额外开启 strict 或手动 only()。
性能影响:开启 strict 会多一次键名比对,但可忽略;真正慢的是反复调用 array_diff_key 做后置过滤,不如前置控制干净。
-
validate($data, $rule, $msg, $type):四个参数里没有字段过滤控制位,纯校验 -
validateScene($data, $scene, $extra = []):TP6 中$extra可传['strict' => true],TP5.1 不支持 - 最稳写法:
$data = $validate->scene('submit')->only(['title', 'content'])->check($data) ? $data : [];,然后只拿这个$data入库
模型 save() 前必须重筛数据,不能信验证器返回值
验证器通过只代表“格式合法”,不代表“字段安全”。$validate->check($data) 返回 true,但 $data 本身没变——里面可能还躺着攻击者塞进来的 delete_time、update_time 甚至 password。
容易踩的坑:写成 if ($validate->check($data)) { $model->save($data); },以为过了验证就万事大吉。
- 务必在
save()前重建数据:用$allowFields = ['name', 'email']; $safeData = array_intersect_key($data, array_flip($allowFields)); - 如果用了
scene,可用$safeData = $validate->getSceneFields('edit');(需自行实现该方法,TP 官方不提供) - 别图省事把整个
$_POST传给验证器再直接传给save()——这是绝大多数绕过案例的起点
复杂点在于:字段白名单要和验证规则、模型允许字段、数据库字段三者对齐;漏一个,就可能成为绕过入口。没人替你检查这三者是否一致,得自己对着看。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











