2

In two places I have found that Laravel csrf protection can be bypassed by setting the protected $except variable. But its not seems to be working according to the doc:

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

and in

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

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

I'm using 5.1

Here is in 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'
]);

And here is the

<?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);
    }
}

And here is what in the BaseVerifier where I am not seeing any $except check:

<?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;
    }
}

However I had solved by commenting out but still setting the $except should have been worked according to the doc; isn't it?:

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

And here is in the error log:

[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))
itsazzad
  • 6,868
  • 7
  • 69
  • 89

3 Answers3

1

Modifying 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

In the $openRoutes array gives your routes and this will be bypassed.

Ariful Haque
  • 3,662
  • 5
  • 37
  • 59
  • 2
    This is *only* if they are using `Laravel 5.0`. If they are using `Laravel 5.1` this is no needed – Laurence Jul 06 '15 at 04:19
1

So for Laravel 5.0 you can use this ;

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);
}

for Laravel 5.1 you can user this feature

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

source on the doc http://laravel.com/docs/5.1/routing#csrf-excluding-uris

Rizerzero
  • 1,120
  • 12
  • 13
0

If you place your webhooks routes in web.php or any other route files, they will require CSRF token. Alternatively, You should place your webhooks routes inside routes/api.php because this file doesn't require CSRF token validation and routes inside api.php won't be validated through VerifyCsrfToken middleware.
Have a look inside boot method in app/Providers/AppServiceProvider you will find:

        $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'));
        });

This means that web routes are protected using middleware group called web while api routes are protected using middleware group called api and both are defined inside app/Http/Kernel.php, if you have a look inside that file, you fill find that web routes are protected using VerifyCsrfToken middleware which causes CSRF verification error while api routes don't have this middleware

    protected $middlewareGroups = [
        'web' => [
            ...,
            \App\Http\Middleware\VerifyCsrfToken::class,
            ...,
        ],

        'api' => [
            'throttle:api',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];
Emad Saeed
  • 106
  • 7