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