广告

解决 AJAX 提交中 Laravel CSRF 失效的完整方法:原因分析、排查步骤与实用代码示例

1. 原因分析

在进行 AJAX 提交时,Laravel 的 CSRF 校验是核心安全机制,用于防止跨站请求伪造攻击。若前端未正确携带 CSRF 令牌,或后端对同源策略、会话 cookie 等因素导致令牌校验失败,通常会返回 419 Page Expired 或 403 错误,导致请求中止。

CSRF 的工作原理依赖于中间件 VerifyCsrfToken,它会将令牌与服务器端的会话令牌进行比对,只有两者一致时才允许请求通过。这就意味着前端需要在每次 AJAX 请求中附带正确的 X-CSRF-TOKEN,并且浏览器必须发送与 Laravel 会话相关的 cookie。

另一个重要因素是 XSRF-TOKEN 与 X-CSRF-TOKEN 的配对关系。多数前端框架会通过 XSRF-TOKEN cookie 读取令牌,然后将其放入 X-CSRF-TOKEN 请求头中。若这层机制被阻断(如跨域、SameSite 设置、域名不匹配等),就会导致 CSRF 失效。

如果你使用的是 SPA 场景或 API+前端分离架构,对 API 路由的 CSRF 处理需要额外关注。默认 Laravel 对 web 路由启用 CSRF,而 api.php 路由通常不强制 CSRF,但若错误地把某些 api 路由放入 VerifyCsrfToken 的检测范围,也会引发问题。

1.1 Laravel CSRF 的工作机制

在 Laravel 中,CSRF 令牌通常保存在会话中,前端通过 meta 标签或隐藏输入框 获取该令牌,并在 AJAX 请求头中提交。若令牌被轮换(例如登录后重新生成令牌),前端若未及时更新,会导致请求失效。

需要注意的是,跨域请求与域名要一致,Cookie 的 Domain 与 SameSite 设定会直接影响令牌的发送。不正确的域名、跨子域请求或严格的 SameSite 策略都会导致令牌无法随请求一同发送,从而触发 CSRF 失败。

2. 排查步骤

在排查 AJAX 提交中 Laravel CSRF 失效的问题时,第一步是从前端入手,确保令牌正确输出、正确注入请求头,并且后端能够正确校验。

首先检查前端模板是否输出 CSRF 令牌,并且在全局 AJAX 设置中统一将令牌放在 X-CSRF-TOKEN 请求头中,以避免局部页面未覆盖的问题。

其次查看浏览器的开发者工具,确认 网络请求中是否携带 X-CSRF-TOKEN,以及是否有同域下的 cookie 发送。若 XSRF-TOKEN cookie 存在但未发送或与 X-CSRF-TOKEN 不匹配,CSRF 仍会失效。

如果使用 Laravel Sanctum 作为 SPA 的认证方案,需明确:在发起任何受保护的请求前,必须先调用 /sanctum/csrf-cookie,以建立 CSRF 保护所需的凭据和 Cookie。

2.1 前端是否输出并使用 CSRF 令牌

确认你的布局模版中包含如下 meta 标签,并且前端在初始化阶段读取该令牌。若缺失,将直接导致 X-CSRF-TOKEN 缺失。

示例(Blade 模板):<meta name="csrf-token" content="{{ csrf_token() }}">

2.2 AJAX 请求头与 Cookie 的配对

请确保所有 AJAX 请求均在请求头中携带 X-CSRF-TOKEN,且浏览器的 Cookie 与域名匹配。若跨子域或跨域访问,请检查 Cookie 的 Domain、Path、SameSite 设置,以及 Access-Control 相关头部。

在前端统一设置示例中,通常使用如下方式:将 meta 令牌注入到 X-CSRF-TOKEN 请求头,并确保 credentials 向后端发送 cookie。

2.3 Sanctum 的 CSRF 流程(SPA/前后端分离)

若使用 Laravel Sanctum 来保护 SPA 的认证,请先执行一次 CSRF cookie 的获取,然后再发送带令牌的请求。未获取 CSRF cookie 就发送需要认证的请求,往往会遇到 CSRF 失效问题。

常见流程包括:首次 GET /sanctum/csrf-cookie,随后所有 API 请求自动带上 X-XSRF-TOKEN 或 X-CSRF-TOKEN(由框架自动处理)。

2.4 服务器端与路由配置排错

查看应用日志,关注 419/CSRF token mismatch 的错误记录。确认 VerifyCsrfToken 中间件是否正确启用,并检查是否把某些 API 路由意外加入了 CSRF 校验范围。

如果你需要对特定路由暂时放开 CSRF,可以在 app/Http/Middleware/VerifyCsrfToken.php 的 $except 属性中列出路由,但要确保这不会带来新的安全风险。

2.5 跨域、SameSite 与会话维度问题

跨域场景下,浏览器对 Cookie 的发送有严格限制。请确认服务器端的 session.cookieDomaincookie 的 SameSite 设置符合你的部署域名结构,避免浏览器阻止会话 Cookie 的发送,从而导致 X-CSRF-TOKEN 与会话不同步。

3. 实用代码示例

下面给出前后端常用的示例代码,帮助你快速在 AJAX 提交中正确携带 CSRF 令牌,并避免失效问题。

在布局中输出 CSRF Meta 标签

<meta name="csrf-token" content="{{ csrf_token() }}">

使用 Axios 统一注入 CSRF 令牌(常见于 Vue/React 项目)

// 在前端入口文件初始化时执行
import axios from 'axios';axios.defaults.headers.common['X-CSRF-TOKEN'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content');

Fetch API 的 CSRF 令牌携带示例

fetch('/api/endpoint', {method: 'POST',headers: {'Content-Type': 'application/json','X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').getAttribute('content')},credentials: 'include',body: JSON.stringify({ key: 'value' })
});

jQuery AJAX 的统一设置

$.ajaxSetup({headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }
});

后端路由与中间件示例(PHP)

解决 AJAX 提交中 Laravel CSRF 失效的完整方法:原因分析、排查步骤与实用代码示例

// 路由示例
Route::post('/example', [ExampleController::class, 'store']);

禁用 CSRF 的示例(谨慎,仅适用于明确信任的场景)

// app/Http/Middleware/VerifyCsrfToken.php
protected $except = ['/webhook/*',
];

Sanctum SPA CSRF 获取示例(前置请求)

// 先获取 CSRF Cookie,再发起后续请求
fetch('/sanctum/csrf-cookie', { credentials: 'include' }).then(() => {// 继续进行需要认证的请求});

广告

后端开发标签