CSRF 保护

简介

Laravel 可以轻松保护应用免受 跨站请求伪造(CSRF)攻击。跨站请求伪造是一种恶意的攻击,它利用已通过身份认证的用户身份来执行未经授权的命令。

Laravel 会自动为应用管理的每个活跃用户会话生成一个 CSRF「令牌」。该令牌用于验证通过身份认证的用户是否是实际向应用发出请求的用户。

只要在应用中定义 HTML 表单,都应该在表单中包含一个隐藏的 CSRF 令牌字段,以便 CSRF 保护中间件可以验证该请求。您可以使用 Blade 指令 @csrf 生成令牌字段:

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

web 中间件组包含的 VerifyCsrfToken 中间件 会自动验证请求输入中的令牌是否与会话中保存的令牌相匹配。

CSRF 令牌 & JavaScript

当构建 Javascript 驱动的应用时,可以很方便地让 JavaScript HTTP 库在发起每个请求时自动加上 CSRF 令牌。默认情况下,resources/js/bootstrap.js 文件使用 Axios HTTP 库注册 csrf-token meta 标签的值。如果您不使用此库,则需要手动对应用进行相应配置。

CSRF 白名单

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

通常来说,您应该将这类路由放在 web 中间件组外面,因为 RouteServiceProvider 会将其应用到 routes/web.php 文件中的所有路由。当然,您也可以通过将它们的 URI 添加到 VerifyCsrfToken 中间件的 $except 属性来排除路由:

namespace App\Http\Middleware;

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

class VerifyCsrfToken extends Middleware
{
    /**
     * CSRF 验证要排除的 URI
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
        'http://example.com/foo/bar',
        'http://example.com/foo/*',
    ];
}

运行测试 时,会自动禁用 CSRF 中间件。

X-CSRF-TOKEN

除了检查 POST 参数中的 CSRF 令牌之外,VerifyCsrfToken 中间件还会检查 X-CSRF-TOKEN 请求头参数。例如,您可以将令牌保存在 HTML meta 标签中:

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

创建 meta 标签后,您就可以使用库(例如 jQuery)自动将令牌添加到所有请求头中。这为基于 AJAX 的应用提供了简单、方便的 CSRF 保护:

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

默认情况下,resources/js/bootstrap.js 文件会用 Axios HTTP 函数库来注册 csrf-token meta 标签中的值。如果您不使用此库,则需要手动对应用进行相应配置。

X-XSRF-TOKEN

Laravel 会将当前 CSRF 令牌保存到应用生成的每个响应的 XSRF-TOKEN Cookie 中。您可以使用该 Cookie 值来设置 X-XSRF-TOKEN 请求头。

发送该 Cookie 主要是为了方便,因为一些 JavaScript 框架或者库(例如 Angular 和 Axios)会自动将其值放到 X-XSRF-TOKEN 请求头中。