跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

ThinkPHP如何做请求参数结构路径合法性白名单_ThinkPHP仅允许指定嵌套路径存在【方法】

ThinkPHP的Validate无法校验嵌套路径存在性,需在验证前用filterRequestData按白名单路径逐层提取合法数据,避免非法字段混入;同时须关闭param_merge、对齐白名单与验证规则、补充类型校验。 ThinkPHP 的
validate
无法直接校验嵌套路径存在性 ThinkPHP 原生的验证器(
Validate
)只校验字段值是否符合规则,不校验「请求中是否只包含白名单路径」。比如你只允许
user.name
和
user.email
,但用户传了
user.password
或
admin.id
,默认不会报错——它压根不检查字段“是否存在”,只检查“存在时是否合法”。 所以不能靠
rule
或
scene
解决路径白名单问题,得在参数进入验证器前做结构过滤。 用
filterRequestData
手动提取白名单路径 核心思路:把原始
input()
数据当树,按白名单路径逐层取值,丢弃所有未声明的键。不是“禁止非法字段”,而是“只保留合法路径”。 白名单定义为二维数组,如
[['user', 'name'], ['user', 'email'], ['status']]
遍历每条路径,在原始数据中用
array_key_exists
+ 递归下标访问取值,遇到中间键不存在就跳过 避免用
isset($data[$k])
,它对
null
值返回 false,而空字符串/0 是合法值 不要用
array_filter
直接删键——它不处理嵌套,且会重排索引,破坏结构 示例片段: 立即学习 “ PHP免费学习笔记(深入) ”; PHP 8.5.5 PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。 下载
function filterRequestData(array $data, array $whitelist): array { $result = []; foreach ($whitelist as $path) { $val = $data; $found = true; foreach ($path as $key) { if (!is_array($val) || !array_key_exists($key, $val)) { $found = false; break; } $val = $val[$key]; } if ($found) { // 按路径写回 result,支持多层重建 $ref = &$result; foreach (array_slice($path, 0, -1) as $k) { if (!isset($ref[$k]) || !is_array($ref[$k])) { $ref[$k] = []; } $ref = &$ref[$k]; } $ref[end($path)] = $val; } } return $result; }
input()
默认递归合并,要防深层污染 ThinkPHP 的
input()
在开启
param_merge
(默认开)时,会把
GET
、
POST
、
PUT
等自动合并,且对同名嵌套键做递归覆盖。比如
POST[user][name]
和
GET[user][password]
同时存在,最终
input('user/a')
可能混入意外字段。 生产环境务必关闭自动合并:
config(['app.param_merge' => false])
统一用
input('post.') + input('get.')
显式指定来源,再进白名单过滤 特别注意
application/route.php
中的变量绑定(如
:id
)也会注入到
input()
,需在路由层或控制器开头就做剥离 白名单路径和验证规则必须严格对齐 很多人把白名单和验证规则分开维护,结果加了一个新字段到白名单,却忘了加验证规则,或者改了规则但漏更新白名单——这会导致“能传进来但不校验”,等于裸奔。 建议把白名单路径和验证规则定义在同一配置文件,例如
config/request_whitelist.php
用键名复用:如
'user.name' => 'require|alphaNum'
,解析时自动拆成路径数组和规则字符串 在控制器基类里统一调用
filterRequestData()
+
Validate::check()
,避免每个方法重复写 注意
scene
场景切换时,白名单也得动态切,否则
create
场景放行
password
,
update
场景却不该放行,但白名单没分场景就会失效 最易被忽略的是:白名单只管“路径存在”,不管“值类型”。比如允许
user.id
,但没限制它必须是整数,攻击者仍可传字符串触发 SQL 隐式转换。白名单是第一道门,后面还得接类型断言和验证规则——两步缺一不可。

相关文章