CSRF 保护

未匹配的标注
本文档最新版为 10.x,旧版本可能放弃维护,推荐阅读最新版!

CSRF 保护

简介

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

漏洞的解释

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

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

<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, PATCHDELETE 为秘密会话值恶意的应用程序无法访问请求。

阻止 CSRF 请求

Laravel 为应用程序管理的每个活动 用户会话 自动生成 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 指令生成隐藏的令牌输入字段:

<form method="POST" action="/profile">
    @csrf
    <!-- 等同于 -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>

App\Http\Middleware\VerifyCsrfToken 中间件,其包括在在 web 由默认中间件基,将自动验证在请求输入的令牌匹配令牌存储在会话。当这两个令牌匹配时,我们知道经过身份验证的用户就是发起请求的用户。

CSRF Tokens & SPAs

如果要构建将 Laravel 用作 API 后端的 SPA Laravel Sanctum 文档 ,以获取有关使用 API 进行身份验证和防范 CSRF 漏洞的信息。

白名单

有时候你可能希望设置一组不需要 CSRF 保护的 URL 。例如,如果你正在使用 Stripe 处理付款并使用了他们的 webhook 系统,你会需要从 CSRF 的保护中排除 Stripe webhook 处理程序路由,因为 Stripe 不知道要发送什么样的 CSRF 令牌到你的路由。

通常,你应该把这类路由放在 web 中间件组之外,因为 routes/web.php 文件中的 App\Providers\RouteServiceProvider 适用于所有路由。不过,你也可以通过将这类 URL 添加到 VerifyCsrfToken 中间件的 $except 属性中来排除对这类路由的 CSRF 保护:

<?php

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 令牌外,App\Http\Middleware\VerifyCsrfToken 中间件还将检查 X-CSRF-TOKEN 请求头。你应该将令牌存储在 HTML meta 标签中:

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

然后,你可以指示类似 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 标头。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/laravel/8.5/csr...

译文地址:https://learnku.com/docs/laravel/8.5/csr...

上一篇 下一篇
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
贡献者:7
讨论数量: 5
发起讨论 只看当前版本


panco
CSRF 真的有用吗
0 个点赞 | 9 个回复 | 问答 | 课程版本 5.7
FakeSPrite
input 里面的 csrf 和 @csrf 的区别?
0 个点赞 | 5 个回复 | 问答 | 课程版本 5.8
Thejoe
请问为什么 form 表单提交 CSRF「令牌」无法使用 @csrf 样式?
0 个点赞 | 4 个回复 | 问答 | 课程版本 5.6
Ewaa
加入了 @csrf 还是报错 419,清除缓存也没用
0 个点赞 | 2 个回复 | 问答 | 课程版本 5.5