Laravel 5:强制使用 csrf 验证 [GET] 请求

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31606926/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-14 12:01:48  来源:igfitidea点击:

Laravel 5: force to validate [GET] requests using csrf

phpsecuritylaravellaravel-5csrf

提问by mwafi

by default Laravel 5 validate & match "tokens" for all [POST] requests, how to tell L5 to validate "GET, PUT & Delete" requests too?

默认情况下,Laravel 5 验证并匹配所有 [POST] 请求的“令牌”,如何告诉 L5 也验证“GET、PUT 和删除”请求?

-> prevent any request without valid token

-> 阻止任何没有有效令牌的请求

thanks,

谢谢,

采纳答案by Romain Lanz

Laravel validate the token for POST, PUT and DELETE. You don't need to validate the token for a GET request if you follow a RESTful system.

Laravel 验证 POST、PUT 和 DELETE 的令牌。如果您遵循 RESTful 系统,则不需要验证 GET 请求的令牌。

From the documentation:

从文档:

You do not need to manually verify the CSRF token on POST, PUT, or DELETE requests. The VerifyCsrfToken HTTP middleware will verify token in the request input matches the token stored in the session.

您无需在 POST、PUT 或 DELETE 请求上手动验证 CSRF 令牌。VerifyCsrfToken HTTP 中间件将验证请求输入中的令牌是否与会话中存储的令牌匹配。

http://laravel.com/docs/5.1/routing#csrf-protection

http://laravel.com/docs/5.1/routing#csrf-protection

回答by Ziki

You can create your own middleware that will take care of it and replace the default Laravel VerifyCsrfToken class. In Laravel 5.3:

您可以创建自己的中间件来处理它并替换默认的 Laravel VerifyCsrfToken 类。在 Laravel 5.3 中:

  1. Create your new middleware php artisan make:middleware VerifyCsrfTokenAll

  2. Replace the middleware class in app/Http/Kernel.php- search for protected $middlewareGroupsand replace VerifyCsrfToken::classby your new middleware. So it can look like this:

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfTokenAll::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        ...
    
  3. In app/Http/Middleware/VerifyCsrfTokenAll.phpmake it extend original verifier and just override the isReading()method as this one is responsible for bypassing the GET requests. Something like this depending on your use case:

    <?php
    namespace App\Http\Middleware;
    
    use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
    
    class VerifyCsrfTokenAll extends BaseVerifier
    {
        /**
         * Determine if the HTTP request uses a ‘read' verb.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return bool
         */
        protected function isReading($request)
        {
            return false;
            // return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
        }
    
    }
    
  1. 创建新的中间件 php artisan make:middleware VerifyCsrfTokenAll

  2. 替换中间件类app/Http/Kernel.php- 搜索protected $middlewareGroups并替换VerifyCsrfToken::class为您的新中间件。所以它看起来像这样:

    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfTokenAll::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
        ...
    
  3. app/Http/Middleware/VerifyCsrfTokenAll.php使其延长原有验证,只是重写isReading()方法,因为这是一个负责绕过GET请求。像这样的事情取决于您的用例:

    <?php
    namespace App\Http\Middleware;
    
    use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
    
    class VerifyCsrfTokenAll extends BaseVerifier
    {
        /**
         * Determine if the HTTP request uses a ‘read' verb.
         *
         * @param  \Illuminate\Http\Request  $request
         * @return bool
         */
        protected function isReading($request)
        {
            return false;
            // return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
        }
    
    }
    

If you only wanted to validate in on certain routes, it is better to do it as a route middleware as in my case - I created a VerifyCsrfTokenGetmiddleware and assigned it in app/Http/Kernelto $routeMiddlewaregroup like this:

如果您只想在某些路由上进行验证,最好将其作为路由中间件来执行,就像我的情况一样 - 我创建了一个VerifyCsrfTokenGet中间件并将其分配app/Http/Kernel到这样的$routeMiddleware组中:

protected $routeMiddleware = [
    'csrf_get' => \App\Http\Middleware\VerifyCsrfTokenGet::class,
    ...

In app/Http/MIddleware/VerifyCsrfTokenGet.phpI did the verification:

app/Http/MIddleware/VerifyCsrfTokenGet.php我做了验证:

public function handle($request, Closure $next)
{
    // check matching token from GET
    $sessionToken = $request->session()->token();
    $token = $request->input('_token');
    if (! is_string($sessionToken) || ! is_string($token) || !hash_equals($sessionToken, $token) ) {
        throw new \Exception('CSRF token mismatch exception');
    }

    return $next($request);
}

and finally assigned this to any route as a csrf_middlewarewhereever I want to validate it, eg. in constructor of some of the controllers:

最后将其分配给任何路线作为csrf_middleware我想验证它的任何地方,例如。在一些控制器的构造函数中:

class InvoicesController extends Controller
{
    function __construct()
    {
        // define middleware
        $this->middleware('csrf_get', ['only' => ['pay', 'createmail']]);
    }

回答by connor

"csrf token" is just an ordinary session value with a key name "_token" ,you can just get and reset this value directly. like this:

"csrf token" 只是一个普通的会话值,键名为 "_token" ,你可以直接获取和重置这个值。像这样:

$token = $this->request->get('_token');
if(is_null($token) || $token!=csrf_token())
    throw new AppException('illegal_pay_operation');
else
    Session::regenerateToken();