ThinkPHP 表单验证默认不校验 CSRF 令牌,需手动启用 token 验证;require 规则基于 empty() 判定,对 0、’0′ 等 falsy 值误判为未提交;自定义验证器中 $this->error 不自动抛异常且不记录日志;验证通过不等于数据安全,入库前须过滤 XSS、路径遍历等风险。

ThinkPHP 表单验证默认不校验 CSRF 令牌
ThinkPHP 的 validate 方法只做字段规则检查,完全不管请求是否来自本站表单。如果你没手动开启 CSRF 防护,攻击者可以构造 POST 请求绕过前端限制直接提交恶意数据。
必须在控制器方法开头加 $this->validateToken()(TP6.1+)或手动比对 token() 生成的值。TP6.0 中需配合中间件 thinkmiddlewareValidateToken 并在配置中启用:'token_on' => true,否则 token() 函数返回空字符串,验证永远失败。
- 模板中必须调用
{:token()}输出隐藏域,且不能被 JS 动态移除或覆盖 - 同一页面多次提交时,TP 默认一次性 token 会失效,需配置
'token_reset' => true允许刷新 - AJAX 提交需额外从响应头或 JSON 数据中提取新 token,否则第二次请求必报
token error
验证规则里写 require 不等于“非空”,它跳过 0、’0’、false 等 falsy 值
TP 的 require 规则底层用的是 PHP 的 empty() 判断,所以传入 0、'0'、[] 都会被当作“未填写”拒绝。这在数字 ID、开关字段、金额输入等场景下极容易出错。
真正要校验“是否提交了该字段”,应该用 isset 场景规则;要校验“是否为非零数值”,得拆成两步:number|gt:0 或自定义闭包验证器。
立即学习“PHP免费学习笔记(深入)”;
-
require→ 适合文本类字段(用户名、邮箱) -
isset→ 适合 checkbox、switch 等可能提交 0/false 的字段 - 数字类字段慎用
require|number,优先用number|between:1,99999999明确范围
自定义验证器中 $this->error 不会自动抛异常,错误信息也不进日志
TP 的验证器类里,$this->error 只是把错误存到属性里,调用方不主动检查 $validate->getError() 就等于什么都没发生。更麻烦的是,默认错误信息不会记录到 runtime/log/,线上出问题时根本看不到用户到底输错了什么。
推荐做法:在控制器中统一处理验证结果,并手动写日志。尤其对手机号、身份证号等敏感字段,建议记录脱敏后的输入值(如 138****1234)和错误规则名,方便排查是规则写错还是用户乱填。
- 不要依赖
validate()->batch()->check()的返回值就结束流程,必须显式判断if (!$validate->check($data)) { ... } - 日志写法示例:
Log::record('验证失败:'.json_encode($validate->getError()).',数据:'.substr($phone,0,3).'****'.substr($phone,-4), 'error'); - 批量验证开启后,
getError()返回数组,但字段名键可能含点号(如user.name),注意前端映射逻辑
数据库写入前没过滤 $_POST,验证通过 ≠ 数据安全
验证只是告诉用户“你填得不对”,不代表数据进了数据库就安全。TP 的 allowField 能防字段注入,但对内容层面的 XSS、SQL 片段、路径遍历毫无作用。比如用户在简介字段提交 <script>alert(1)</script>,验证器只要求“长度 1–100”,它就畅通无阻。
真正该做的:在验证通过后、入库前,对每项数据做针对性过滤。TP 自带的 filter 参数仅支持简单函数(如 htmlspecialchars),复杂场景必须手写清理逻辑——例如富文本字段保留部分 HTML,但删掉 <script></script> 和 onerror= 类属性。
- 敏感字段(标题、昵称、搜索关键词)强制走
htmlspecialchars($value, ENT_QUOTES, 'UTF-8') - 文件上传路径拼接前,务必用
basename()截取原始文件名,防止../../../etc/passwd - 用
Db::name()->insert()代替原生 SQL 拼接,哪怕只是简单 INSERT,也别省那两个括号
验证规则写得再全,挡不住没关的 token 开关;错误提示打得再细,救不了没记的日志;表单拦得再严,防不了入库前的脏数据——安全不是某个函数调用的结果,是每个环节的克制和确认。
文章来自机圈观察员网,发布者:,转载请注明出处:https://www.jqgcy.com/shoujipingce/124093.html