ThinkPHP5的CSRF防护默认关闭,表单报“非法请求”主因是配置缺失或校验断链:未设token_on=true、控制器未调checkToken()、URL参数不一致、缓存复用旧token、输入流被提前消耗或session存储异常。

ThinkPHP5 的 CSRF 防护默认是关闭的,token() 函数只生成值,不自动校验;不配 token_on = true、不调用 validateToken() 或没走中间件,就等于没防。
为什么表单提交总报“非法请求”或“token error”
这不是被攻击了,而是配置/调用链断在某个环节:
-
token_on = true没写进config/app.php—— ThinkPHP5 不读控制器里的变量,只认配置文件 - 模板里用了
{:token()},但控制器方法里没调$this->request->token()或Request::token() - 表单 action 是带 query 参数的 URL(如
/user/edit?id=123),而 token 默认按无参路径生成,两者不匹配 - 页面被浏览器或 CDN 缓存,
{:token()}渲染一次后反复复用旧值,session 里 token 却已刷新 - 中间件(如日志、调试)提前调了
input('post.')或file_get_contents('php://input'),导致原始 POST 数据流被消耗,validateToken()拿不到__token__字段
如何正确启用并验证 token(ThinkPHP5 实操)
ThinkPHP5 不靠中间件自动拦截,必须手动触发校验。关键动作分三步走:
- 在
config/app.php中开启全局开关:'token_on' => true,同时建议设'token_name' => 'csrf_token'(改默认名降低扫描风险) - 在需要防护的控制器方法开头加:
$this->request->token();—— 这会自动调用validateToken()并抛异常 - 若需自定义逻辑(比如 AJAX 提交后不跳转),改用:
if (!$this->request->checkToken()) { $this->error('非法请求'); } - 注意:
checkToken()默认绑定当前完整 URL 路径,如要忽略 query 参数,得传参:$this->request->checkToken('', false)
AJAX 提交时 token 怎么传才不失败
ThinkPHP5 的 {:token()} 只输出 HTML,不会自动注入到 JS 请求头里。前端必须显式携带,否则校验必过不了:
立即学习“PHP免费学习笔记(深入)”;
- 模板中确保有:
{:token()}—— 它会生成<input type="hidden" name="__token__" value="xxx"> - AJAX 请求体里必须带上这个值:
$.post('/user/save', { name: 'a', __token__: $('input[name=__token__]').val() }) - 不要在 JS 里重新调
token()—— 它返回的是新值,和 session 里不一致;也不要硬编码 token 值 - Vue/React 项目中,token 必须由后端渲染进初始 HTML 的
<meta>或全局 JS 变量里,不能靠前端生成
token 失效太快?多标签页、重复打开页面怎么办
这是 ThinkPHP5 的设计行为:每次渲染 {:token()} 就刷新 session 里的 token,旧页面表单自然失效。这不是 bug,但影响体验:
- 别关全局
token_on,应按路由排除 —— 在路由定义里加'except' => ['api/upload'] - 对允许重复提交的场景(如搜索框),用
token(null, false)关闭 URL 绑定,或用token(null, true, true)启用多次验证(第三个参数为true) - 更可控的方式是绕过自动机制:手动生成存入 session:
session('csrf_token', token());,再用Request::checkToken(session('csrf_token'))显式比对 - 调试时可 dump:
session('__token__')和input('__token__'),确认两者是否一致、是否为空
最易被忽略的一点:ThinkPHP5 的 token 校验强依赖 session 正常读写。换 Redis 存 session 时,若没复用 handler 实例或开了 use_trans_id,token 值在验证时根本取不到 —— 表现就是“明明填了却总错”,问题不在表单,而在 session 底层。



















