CSRF防护
CSRF(跨站请求伪造)防护用于防止恶意网站冒充当前用户提交表单或发送请求。
启用方式
StartMVC 推荐通过全局中间件开启 CSRF 防护。启用后,POST、PUT、DELETE、PATCH 请求会自动校验 Token。
config/middleware.php
return [
'global' => [
'app\\middleware\\CsrfMiddleware',
],
];配置
在 config/common.php 中配置:
'csrf' => [
'token_lifetime' => 3600, // Token有效期(秒)
'token_name' => 'csrf_token', // Token字段名
'auto_delete' => false, // 验证后是否自动删除
'exclude' => [ // 无需校验的路径,支持 * 通配符
// 'api/webhook',
// 'api/open/*',
],
],推荐配置:
- 普通表单:
token_lifetime => 3600 - 敏感操作:
token_lifetime => 300,auto_delete => true - 长表单:
token_lifetime => 7200
视图中使用
普通表单
推荐使用 csrf_field() 生成隐藏域:
<form method="post" action="/save">
<?php echo csrf_field(); ?>
<input type="text" name="title">
<button type="submit">提交</button>
</form>
AJAX 请求
在页面 <head> 中输出:
<?php echo csrf_meta(); ?>
前端请求示例:
<script>
const token = document.querySelector('meta[name="csrf-token"]').content;
fetch('/save', {
method: 'POST',
headers: {
'X-CSRF-TOKEN': token,
'Content-Type': 'application/json'
},
body: JSON.stringify({title: 'test'})
});
</script>
手动获取 Token
<?php echo csrf_token(); ?>
特殊场景
一次性 Token
适合删除、支付、确认操作等敏感请求:
$token = \startmvc\core\Csrf::token(false, 300);
配合配置:
'auto_delete' => true
表示验证成功后立即失效。
排除校验路径
以下场景通常需要排除 CSRF 校验:
- 第三方支付回调
- Webhook 回调
- 对外开放 API
示例:
'exclude' => [
'api/webhook',
'api/open/*',
],
常用方法
\startmvc\core\Csrf::token(); // 获取或生成Token
\startmvc\core\Csrf::token(false, 300); // 指定有效期
\startmvc\core\Csrf::check(); // 手动校验
\startmvc\core\Csrf::check(true); // 校验后删除
\startmvc\core\Csrf::refresh(); // 刷新Token
\startmvc\core\Csrf::getTokenTTL(); // 获取剩余有效时间
\startmvc\core\Csrf::unsetToken(); // 删除Token
说明:
- 已启用
CsrfMiddleware时,通常不需要在控制器中重复调用Csrf::check() Csrf::check()主要用于未走中间件的特殊场景
Token 提交方式
系统按以下顺序读取 Token:
- POST 字段:
csrf_token - 请求头:
X-CSRF-TOKEN - 请求头:
X-XSRF-TOKEN
常见问题
提示 403 或“CSRF token 验证失败”?
检查表单是否输出了 csrf_field(),或 AJAX 是否正确传递了请求头。
页面停留太久后提交失败?
说明 Token 已过期,可适当增大 token_lifetime。
刷新页面后旧表单失效?
请检查是否启用了 auto_delete => true。
多标签页会冲突吗?
默认不会。只要 Token 未过期且未被删除,就可以重复使用。