[ Laravel 5.4 文档 ] HTTP层 —— CSRF保护

1、简介

跨站请求伪造(CSRF)是一种通过伪装授权用户的请求来利用授信网站的恶意漏洞。Laravel 让应用避免遭到跨站请求伪造攻击变得简单。

Laravel 自动为每一个被应用管理的有效用户会话生成一个 CSRF “令牌”,该令牌用于验证授权用户和发起请求者是否是同一个人。

任何时候在 Laravel 应用中定义 HTML 表单,都需要在表单中引入 CSRF 令牌字段,这样 CSRF 保护中间件才能够正常验证请求。要想生成包含 CSRF 令牌的隐藏输入字段,可以使用辅助函数 csrf_field 来实现:

<form method="POST" action="/profile">
    {{ csrf_field() }}
    ...
</form>

中间件组 web 中的中间件 VerifyCsrfToken 会自动为我们验证请求输入的 token 值和 Session 中存储的 token 是否一致。

2、从 CSRF 保护中排除指定 URL

有时候我们需要从 CSRF 保护中排除一些 URL,例如,如果你使用了 Stripe 来处理支付并用到他们的 webhook 系统,这时候就需要从 Laravel 的 CSRF 保护中排除 webhook 处理器路由,因为 Stripe 并不知道要传什么 token 值给我们定义的路由。

通常我们需要将这种类型的路由放到文件 routes/web.php 里,排除在中间件组 web 之外。不过,你也可以在 VerifyCsrfToken 中间件中将要排除的 URL 添加到 $except 属性数组:

<?php

namespace App\Http\Middleware;

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

class VerifyCsrfToken extends BaseVerifier
{
    /**
     *从CSRF验证中排除的URL
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
    ];
}

3、X-CSRF-Token

除了将 CSRF 令牌作为 POST 参数进行验证外,还可以通过设置 X-CSRF-Token 请求头来实现验证,VerifyCsrfToken 中间件会检查 X-CSRF-TOKEN 请求头。实现方式如下,首先创建一个 meta 标签并将令牌保存到该 meta 标签:

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

然后在 js 库(如 jQuery)中添加该令牌到所有请求头,这为基于 AJAX 的应用提供了简单、方便的方式来避免 CSRF 攻击:

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

4、X-XSRF-Token

Laravel 还会将 CSRF 令牌保存到名为 XSRF-TOKEN 的 Cookie 中,你可以使用该 Cookie 值来设置 X-XSRF-TOKEN 请求头。

一些 JavaScript 框架,比如 Angular,会为你自动进行设置,基本上你不太需要手动设置这个值。

学院君 has written 980 articles

Laravel学院院长,终身学习者

积分:112722 等级:P12 职业:手艺人 城市:杭州

8 条回复

  1. 志不在高 志不在高 says:
    很赞,我还纳闷呢,谢谢解答
  2. 风 says:
    设置$except无效,是因为这个原因么 ?
  3. 学院君 学院君 says:
    放到表单里也能看到 重点不在能不能看到 重点在于针对每个请求token独一份 别人伪造不了
  4. hrc hrc says:
    把csrf_token放在meta里不是直接就能看到了?
  5. 激励 激励 says:
    csrf_field() == csrf_token() =="xFrEozENzBRaN7oHDXKjxKQhIhWOHAWoLMC0V9yo"
  6. 饶帆 饶帆 says:
    这里写错了,CSRF保护的第2节:“通常我们需要将这种类型的路由放到文件 routes/web.php 里,排除在中间件组 web 之外。” 应该是api.php,不是web.php
  7. admin admin says:
    csrf_field() 是生成 隐藏输入字段,内含 CSRF 令牌 csrf_token() 是生成 CSRF 令牌
  8. 绿豆包包 绿豆包包 says:
    csrf_field 不显示 是csrf_token 吧= =

登录后才能进行评论,立即登录?