Laravel - CSRF


路由篇中我们已经讲过了 POST - PUT - DELTE 请求的时候需要使用到 CSRF。

在前端的模板中,我们可以使用以下方式来生成 CSRF.

[ Blade 中使用CSRF ]

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

blade模板会自动为我们完成这件事情。

[ META 中使用CSRF ]

除了可以在表单中使用,还可在Meta中添加 CSRF

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

一旦创建了 meta 标签,你就可以使用类似 jQuery 的库将令牌自动添加到所有请求的头信息中。这可以为您基于 AJAX 的应用提供简单、方便的 CSRF 保护。

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

填写在meta中,很适合单页程序使用,vue ,NG,之类的单页应用。

[ 关于CSRF白名单 ]

CSRF 是由中间件所控制的。在 App\Http\kernel.php 文件中, 我们可以看到

<?php

...

protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
];

...
?>

这里说明所有使用了 web中间件的文件,都会触发CSRF中间件。如果你不需要使用CSRF中间件,那就不要让你的路由排除在web中间件之外。

当然也有其他方法。我们可以在 VerifyCsrfToken.php 中添加除外路由。

<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        //指定路由不使用CSRF验证
    ];
}
?>

当然也可以另一种方式,修改 handle 方法。可以更加灵活,还可以做逻辑处理。

<?php
namespace App\Http\Middleware;

//添加Closure引用,否则会报错
use Closure;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
    /**
     * The URIs that should be excluded from CSRF verification.
     *
     * @var array
     */
    protected $except = [
        //指定路由不使用CSRF验证
    ];

    public function handle($request, Closure $next)
    {
        //如果路由是 example7. 那就不检测
        if ( ! $request->is('example7'))
        {
            return parent::handle($request, $next);
        }
        return $next($request);
    }
}

results matching ""

    No results matching ""