【问题标题】:Laravel: webhooks need to bypass Laravel's CSRF verificationLaravel:webhooks 需要绕过 Laravel 的 CSRF 验证
【发布时间】:2015-09-23 01:16:06
【问题描述】:

在两个地方我发现可以通过设置protected $except 变量来绕过 Laravel csrf 保护。但它似乎没有根据文档工作:

http://laravel.com/docs/5.1/billing#handling-stripe-webhooks

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

protected $except = [
    'stripe/*',
];

我正在使用 5.1

在 routes.php 中

Route::match(['post'], '/webhooks/provider/callback/{version}', [
    'as' => 'provider.webhooks.callback', 'uses' => 'WebhookController@callback'
]);
Route::match(['post'], '/webhooks/provider/fallback/{version}', [
    'as' => 'provider.webhooks.fallback', 'uses' => 'WebhookController@fallback'
]);

这里是

<?php namespace App\Http\Middleware;
use Closure;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier {
    protected $except = [
        'webhooks/*',
        '/webhooks/*',
    ];
    public function handle($request, Closure $next)
    {
        return parent::handle($request, $next);
    }
}

这是BaseVerifier 中我没有看到任何$except 检查的内容:

<?php namespace Illuminate\Foundation\Http\Middleware;
use Closure;
use Illuminate\Contracts\Routing\Middleware;
use Symfony\Component\HttpFoundation\Cookie;
use Illuminate\Contracts\Encryption\Encrypter;
use Illuminate\Session\TokenMismatchException;
use Symfony\Component\Security\Core\Util\StringUtils;
class VerifyCsrfToken implements Middleware {
    public function handle($request, Closure $next)
    {
        if ($this->isReading($request) || $this->tokensMatch($request))
        {
            return $this->addCookieToResponse($request, $next($request));
        }

        throw new TokenMismatchException;
    }
}

但是我已经通过注释解决了,但仍然按照文档设置 $except 应该已经工作了;不是吗?:

<?php namespace App\Http;
use Illuminate\Foundation\Http\Kernel as HttpKernel;
class Kernel extends HttpKernel {
    protected $middleware = [
        //'App\Http\Middleware\VerifyCsrfToken',
    ];
}

这是在错误日志中:

[2015-07-06 09:40:34] production.ERROR: exception 'Illuminate\Session\TokenMismatchException' in /vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php:46
Stack trace:
#0 /app/Http/Middleware/VerifyCsrfToken.php(26): Illuminate\Foundation\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))
#1 /vendor/laravel/framework/src/Illuminate/Pipeline/Pipeline.php(125): App\Http\Middleware\VerifyCsrfToken->handle(Object(Illuminate\Http\Request), Object(Closure))

【问题讨论】:

  • 您可以发布您的路线文件吗?您是否将路由设置为“/stripe/webhook”?
  • 你使用的是 Laravel 5.1 吗?
  • 是的,它的 5.1 @TheShiftExchange
  • 你能发布你的路线吗?
  • 你确定它是 5.1 吗?因为 BaseVerifer 来自 5.0 - 而不是 5.1

标签: laravel laravel-5 laravel-routing


【解决方案1】:

修改app/Http/Middleware/VerifyCsrfToken.php

//add an array of Routes to skip CSRF check
private $openRoutes = ['free/route', 'free/too'];

//modify this function
public function handle($request, Closure $next)
    {
        //add this condition 
    foreach($this->openRoutes as $route) {

      if ($request->is($route)) {
        return $next($request);
      }
    }

    return parent::handle($request, $next);
  }

source

$openRoutes 数组中给出了您的路线,这将被绕过。

【讨论】:

  • 如果他们使用Laravel 5.0。如果他们使用Laravel 5.1,则不需要
【解决方案2】:

所以对于 Laravel 5.0,你可以使用这个;

private $openRoutes = ['webhooks/free', 'webhooks/*'];

public function handle($request, Closure $next)
{
   if(in_array($request->path(), $this->openRoutes)){
    return $next($request);
   }

    return parent::handle($request, $next);
}

对于 Laravel 5.1,您可以使用此功能

<?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 = [
                       'stripe/*',
                     ];
 }

文档来源 http://laravel.com/docs/5.1/routing#csrf-excluding-uris

【讨论】:

    【解决方案3】:

    如果您将 webhook 路由放在 web.php 或任何其他路由文件中,它们将需要 CSRF 令牌。或者,您应该将 webhook 路由放在 routes/api.php 内,因为此文件不需要 CSRF 令牌验证,并且 api.php 内的路由不会通过 VerifyCsrfToken 中间件进行验证。
    看看app/Providers/AppServiceProvider 中的boot 方法,你会发现:

            $this->routes(function () {
                Route::prefix('api')
                    ->middleware('api')
                    ->namespace($this->namespace)
                    ->group(base_path('routes/api.php'));
    
                Route::middleware('web')
                    ->namespace($this->namespace)
                    ->group(base_path('routes/web.php'));
            });
    

    这意味着web 路由使用名为web 的中间件组进行保护,而api 路由使用名为api 的中间件组进行保护,并且两者都在app/Http/Kernel.php 中定义,如果您查看该文件的话,您填写发现web 路由使用VerifyCsrfToken 中间件进行保护,这会导致CSRF 验证错误,而api 路由没有此中间件

        protected $middlewareGroups = [
            'web' => [
                ...,
                \App\Http\Middleware\VerifyCsrfToken::class,
                ...,
            ],
    
            'api' => [
                'throttle:api',
                \Illuminate\Routing\Middleware\SubstituteBindings::class,
            ],
        ];
    

    【讨论】:

      猜你喜欢
      • 2019-11-04
      • 2015-09-22
      • 2021-06-29
      • 1970-01-01
      • 2014-06-06
      • 1970-01-01
      • 1970-01-01
      • 2011-10-04
      • 1970-01-01
      相关资源
      最近更新 更多