CSRF保护

Introduction

跨站点请求伪造是一种恶意利用,代表经过身份验证的用户执行未经授权的命令。值得庆幸的是,Laravel 可以轻松保护您的应用程序免受跨站请求伪造 (CSRF) 攻击。

漏洞的解释

如果您不熟悉跨站点请求伪造,让我们讨论一个如何利用此漏洞的示例。假设您的应用程序有一个/user/email 接受的路线POST 请求更改经过身份验证的用户的电子邮件地址。最有可能的是,这条路线需要一个email 输入字段包含用户想要开始使用的电子邮件地址。

如果没有 CSRF 保护,恶意网站可能会创建指向您应用程序的 HTML 表单/user/email 路由并提交恶意用户自己的电子邮件地址:

<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 令牌可以通过请求的会话或通过csrf_token 辅助功能:

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 指令:

<form method="POST" action="/profile">
    @csrf

    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

App\Http\Middleware\VerifyCsrfToken middleware,它包含在web 默认情况下,中间件组会自动验证请求输入中的令牌是否与会话中存储的令牌匹配。当这两个令牌匹配时,我们知道经过身份验证的用户是发起请求的用户。

CSRF 代币和 SPA

如果你正在构建一个使用 Laravel 作为 API 后端的 SPA,你应该参考Laravel Sanctum 文档 有关使用 API 进行身份验证和防止 CSRF 漏洞的信息。

从 CSRF 保护中排除 URI

有时您可能希望将一组 URI 排除在 CSRF 保护之外。例如,如果您正在使用Stripe 要处理付款并使用他们的 webhook 系统,您需要将 Stripe webhook 处理程序路由排除在 CSRF 保护之外,因为 Stripe 不知道要向您的路由发送什么 CSRF 令牌。

通常,您应该将这些类型的路由放在web 中间件组App\Providers\RouteServiceProvider 适用于所有路线routes/web.php 文件。但是,您也可以通过将它们的 URI 添加到$except 的财产VerifyCsrfToken 中间件:

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

Note
为方便起见,CSRF 中间件会自动禁用所有路由运行测试.

X-CSRF-TOKEN

除了检查 CSRF 令牌作为 POST 参数外,App\Http\Middleware\VerifyCsrfToken 中间件还将检查X-CSRF-TOKEN 请求标头。例如,您可以将令牌存储在 HTML 中meta 标签:

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

然后,您可以指示像 jQuery 这样的库自动将令牌添加到所有请求标头。这为使用遗留 JavaScript 技术的基于 AJAX 的应用程序提供了简单、方便的 CSRF 保护:

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

X-XSRF-TOKEN

Laravel 将当前的 CSRF 令牌存储在一个加密的XSRF-TOKEN 框架生成的每个响应中包含的 cookie。您可以使用 cookie 值来设置X-XSRF-TOKEN 请求标头。

此 cookie 主要是为了方便开发人员而发送的,因为一些 JavaScript 框架和库(如 Angular 和 Axios)会自动将其值放在X-XSRF-TOKEN同源请求的标头。

Note
默认情况下,resources/js/bootstrap.js 文件包含 Axios HTTP 库,它将自动发送X-XSRF-TOKEN 标题给你。

豫ICP备18041297号-2