CSRF 保护
简介
跨站请求伪造是一种恶意利用方式,它代表已认证的用户执行未授权的命令。幸运的是,Laravel 可以轻松保护你的应用程序免受跨站请求伪造 (CSRF) 攻击。
漏洞解释
如果你不熟悉跨站请求伪造,让我们讨论一个关于如何利用此漏洞的示例。 假设你的应用程序有一个 /user/email
路由,它接受 POST
请求来更改已认证用户的电子邮件地址。 很可能,此路由期望 email
输入字段包含用户想要开始使用的电子邮件地址。
在没有 CSRF 保护的情况下,恶意网站可以创建一个 HTML 表单,该表单指向你的应用程序的 /user/email
路由并提交恶意用户自己的电子邮件地址
1<form action="https://your-application.com/user/email" method="POST">3</form>4 5<script>6 document.forms[0].submit();7</script>
如果恶意网站在页面加载时自动提交表单,则恶意用户只需要诱骗你应用程序中毫无戒心的用户访问他们的网站,他们的电子邮件地址将在你的应用程序中被更改。
为了防止此漏洞,我们需要检查每个传入的 POST
、PUT
、PATCH
或 DELETE
请求,以查找恶意应用程序无法访问的秘密 session 值。
防止 CSRF 请求
Laravel 会为应用程序管理的每个活动用户 session 自动生成一个 CSRF “token”。 此 token 用于验证已认证的用户是否是实际向应用程序发出请求的人。 由于此 token 存储在用户的 session 中,并且每次 session 重新生成时都会更改,因此恶意应用程序无法访问它。
当前 session 的 CSRF token 可以通过请求的 session 或 csrf_token
辅助函数访问
1use Illuminate\Http\Request;2 3Route::get('/token', function (Request $request) {4 $token = $request->session()->token();5 6 $token = csrf_token();7 8 // ...9});
每当你应用程序中定义 “POST”、“PUT”、“PATCH” 或 “DELETE” HTML 表单时,都应该在表单中包含一个隐藏的 CSRF _token
字段,以便 CSRF 保护中间件可以验证请求。 为了方便起见,你可以使用 @csrf
Blade 指令来生成隐藏的 token 输入字段
1<form method="POST" action="/profile">2 @csrf3 4 <!-- Equivalent to... -->5 <input type="hidden" name="_token" value="{{ csrf_token() }}" />6</form>
默认情况下,包含在 web
中间件组中的 Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
中间件将自动验证请求输入中的 token 是否与存储在 session 中的 token 匹配。 当这两个 token 匹配时,我们就知道已认证的用户是发起请求的人。
CSRF Token 和 SPA
如果你正在构建一个将 Laravel 用作 API 后端的 SPA,你应该查阅 Laravel Sanctum 文档,以获取有关使用你的 API 进行身份验证和防止 CSRF 漏洞的信息。
从 CSRF 保护中排除 URI
有时你可能希望从 CSRF 保护中排除一组 URI。 例如,如果你正在使用 Stripe 处理付款并使用他们的 webhook 系统,你将需要从 CSRF 保护中排除你的 Stripe webhook 处理程序路由,因为 Stripe 不知道要将什么 CSRF token 发送到你的路由。
通常,你应该将此类路由放置在 Laravel 应用于 routes/web.php
文件中所有路由的 web
中间件组之外。 但是,你也可以通过将它们的 URI 提供给你应用程序的 bootstrap/app.php
文件中的 validateCsrfTokens
方法来排除特定路由
1->withMiddleware(function (Middleware $middleware) {2 $middleware->validateCsrfTokens(except: [3 'stripe/*',4 'http://example.com/foo/bar',5 'http://example.com/foo/*',6 ]);7})
为了方便起见,在运行测试时,CSRF 中间件会自动为所有路由禁用。
X-CSRF-TOKEN
除了检查作为 POST 参数的 CSRF token 外,默认情况下包含在 web
中间件组中的 Illuminate\Foundation\Http\Middleware\ValidateCsrfToken
中间件还将检查 X-CSRF-TOKEN
请求标头。 例如,你可以将 token 存储在 HTML meta
标签中
1<meta name="csrf-token" content="{{ csrf_token() }}">
然后,你可以指示像 jQuery 这样的库自动将 token 添加到所有请求标头。 这为使用旧版 JavaScript 技术的基于 AJAX 的应用程序提供了简单、方便的 CSRF 保护
1$.ajaxSetup({2 headers: {3 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')4 }5});
X-XSRF-TOKEN
Laravel 将当前的 CSRF token 存储在加密的 XSRF-TOKEN
Cookie 中,该 Cookie 包含在框架生成的每个响应中。 你可以使用 Cookie 值来设置 X-XSRF-TOKEN
请求标头。
此 Cookie 主要作为开发人员的便利发送,因为某些 JavaScript 框架和库(如 Angular 和 Axios)会自动将其值放在同源请求的 X-XSRF-TOKEN
标头中。
默认情况下,resources/js/bootstrap.js
文件包含 Axios HTTP 库,它将自动为你发送 X-XSRF-TOKEN
标头。