跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

ThinkPHP如何防止URL注入_路由参数正则强制校验【教程】

ThinkPHP路由参数:id必须用pattern()显式正则约束,否则任意字符串都合法;它不校验注入元字符,需预检用户正则安全性;验证器不自动处理路由变量,须手动提取并校验。 ThinkPHP 的
:id
这类 路由 参数默认不校验格式,
user/abc
会直接把
$id = 'abc'
传进控制器——这不是“灵活性”,是注入入口。 路由参数必须用
pattern()
显式约束
pattern()
是唯一能对
:xxx
形式路径变量做正则校验的机制,不加它,任何字符串都算合法。 只对
:xxx
生效,
/:xxx?
或
?id=123
不走这条路,得另配验证器 必须写在路由定义链上,比如
Route::get('user/:id', 'User/read')->pattern(['id' => '\d+'])
多个参数一起约束:
->pattern(['id' => '\d+', 'token' => '[a-zA-Z0-9_]{16,32}'])
别写
\d+
就完事——要防回溯爆炸,优先用原子组或限制长度,例如
[1-9]\d{0,7}
(1~8位正整数)
pattern()
不校验注入元字符,得自己拦
(*COMMIT)
类 PCRE 指令 TP 的
pattern()
只管你传的值是否匹配正则,不管这个正则本身安不安全。攻击者若提交
/(?{system("id")})/
这种恶意模式(虽罕见但可能),框架不会报错。 真正危险的是:你把用户输入当正则去
preg_match()
—— 这属于运行时编译,TP 不介入 必须在调用
preg_match($userPattern, $data)
前预检:
strpos($userPattern, "\x00") !== false
、过滤控制字符、再用
@preg_match($userPattern, '')
+
preg_last_error() === PREG_NO_ERROR
别试图用正则去“清洗”正则——
preg_replace('/\(\*\w+/i', '', $input)
极易漏判,白名单预检更可靠 路由参数不进
$request->param()
,验证器不会自动校验它 很多人以为写了
['id' => 'require|number']
就万事大吉,但验证器默认只处理
$request->param()
(即 GET/POST/PUT 数据),
:id
是从 URL 路径解析出来的,根本不在里面。 立即学习 “ PHP免费学习笔记(深入) ”; 手动提取:
$id = $this->request->route('id')
或
input('id')
(注意后者默认不读路由变量,得加
/s
修饰符:
input('id/s')
) 构造数组显式校验:
$validate->check(['id' => $id])
,不能依赖自动绑定 如果用
exists:user,id
规则,确保数据库查询走参数绑定,不是字符串拼接:
where(['id' => $id])
,不是
"id = $id"
最常被跳过的点:路由参数校验是两层动作——
pattern()
拦住非法格式,验证器补足业务逻辑(如存在性、权限)。少一层,就等于把门虚掩着让攻击者推。

相关文章