# CSRF 保护 - [简介](#csrf-introduction) - [阻止 CSRF 请求](#preventing-csrf-requests) - [排除 URL](#csrf-excluding-uris) - [X-CSRF-Token](#csrf-x-csrf-token) - [X-XSRF-Token](#csrf-x-xsrf-token) ## 简介 跨站点请求伪造是一种恶意利用,利用这种手段,代表经过身份验证的用户执行未经授权的命令。值得庆幸的是,Laravel 可以轻松保护您的应用程序免受 [跨站点请求伪造](https://en.wikipedia.org/wiki/Cross-site_request_forgery) (CSRF)攻击。 #### 漏洞的解释 如果您不熟悉跨站点请求伪造,让我们讨论一个如何利用此漏洞的示例。假设您的应用程序具有一个 `/user/email` 接受 `POST` 更改身份验证用户的电子邮件地址的请求的路由。最有可能的是,此路由希望 `email` 输入字段包含用户希望开始使用的电子邮件地址。 没有 CSRF 保护,恶意网站可能会创建指向您的应用程序 `/user/email` 路由的 HTML 表单,并提交恶意用户自己的电子邮件地址:
如果恶意网站在页面加载时自动提交了表单,则恶意用户只需要诱使您的应用程序的一个毫无戒心的用户访问他们的网站,他们的电子邮件地址就会在您的应用程序中更改。 为了防止这种漏洞,我们需要检查每一个传入的 `POST`, `PUT`, `PATCH` 或 `DELETE` 为秘密会话值恶意的应用程序无法访问请求。 ## 阻止 CSRF 请求 Laravel 为应用程序管理的每个活动 [用户会话](/docs/laravel/8.x/session) 自动生成 CSRF 「令牌」。此令牌用于验证经过身份验证的用户是实际向应用程序发出请求的人。由于此令牌存储在用户的会话中,并且每次重新生成会话时都会更改,因此恶意应用程序将无法访问它。 当前会话的CSRF令牌可以通过请求的会话或通过 `csrf_token` 辅助函数进行访问: use Illuminate\Http\Request; Route::get('/token', function (Request $request) { $token = $request->session()->token(); $token = csrf_token(); // ... }); 每当您在应用程序中定义HTML表单时,都应在表单中包含一个隐藏的 CSRF `_token` 字段,以便 CSRF 保护中间件可以验证请求。为了方便起见,您可以使用 `@csrf` Blade 指令生成隐藏的令牌输入字段: `App\Http\Middleware\VerifyCsrfToken` [中间件](/docs/laravel/8.x/middleware),其包括在在 `web` 由默认中间件基,将自动验证在请求输入的令牌匹配令牌存储在会话。当这两个令牌匹配时,我们知道经过身份验证的用户就是发起请求的用户。 ### CSRF Tokens & SPAs 如果要构建将 Laravel 用作 API 后端的 SPA [Laravel Sanctum 文档](/docs/laravel/8.x/sanctum) ,以获取有关使用 API 进行身份验证和防范 CSRF 漏洞的信息。 ### 白名单 有时候你可能希望设置一组不需要 CSRF 保护的 URL 。例如,如果你正在使用 [Stripe](https://stripe.com) 处理付款并使用了他们的 webhook 系统,你会需要从 CSRF 的保护中排除 Stripe webhook 处理程序路由,因为 Stripe 不知道要发送什么样的 CSRF 令牌到你的路由。 通常,你应该把这类路由放在 `web` 中间件组之外,因为 `routes/web.php` 文件中的 `App\Providers\RouteServiceProvider` 适用于所有路由。不过,你也可以通过将这类 URL 添加到 `VerifyCsrfToken` 中间件的 `$except` 属性中来排除对这类路由的 CSRF 保护: 技巧:为了方便,当 [运行测试](/docs/laravel/8.x/testing) 时,所有路由的 CSRF 中间件都会自动禁用。 ## X-CSRF-TOKEN 除了检查 POST 参数中的 CSRF 令牌外,`App\Http\Middleware\VerifyCsrfToken` 中间件还将检查 `X-CSRF-TOKEN` 请求头。你应该将令牌存储在 HTML `meta` 标签中: 然后,你可以指示类似 jQuery 的库将令牌自动添加到所有请求标头中。这可以为基于 AJAX 的应用程序提供简单、便捷的 CSRF 保护: $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); ## X-XSRF-TOKEN Laravel 将当前的 CSRF 令牌存储在一个加密的 `XSRF-TOKEN` cookie 中,该 cookie 包含在框架生成的每个响应中。您可以使用 cookie 值来设置 `X-XSRF-TOKEN` 请求头。 这个 cookie 主要是为了方便开发人员,因为一些 JavaScript 框架和库,比如 Angular 和 Axios,会在同源请求时自动把它的值放在 `X-XSRF-TOKEN` 头中。 > 技巧:默认情况下,`resources/js/bootstrap.js` 文件包含 Axios HTTP 库,它将自动为你发送 `X-XSRF-TOKEN` 标头。