[L5] Disable CSRF Middleware on certain routes

Published 3 years ago by markvdputten

Hi all,

I have found plenty of solutions on how to rip the CSRF Middleware out of L5 alltogether... but what im wondering is if there would be an option to just exclude certain routes from the CSRF Middleware.

Anyone any ideas?

Thanks!

Best Answer (As Selected By markvdputten)
bestmomo

One way is to extend the VerifyCsrfToken and have an array of no csrf urls inside :

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Session\TokenMismatchException;

class VerifyCsrfToken extends \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken {

    protected $except_urls = [
        'contact/create',
        'contact/update',
        ...
    ];

    public function handle($request, Closure $next)
    {
        $regex = '#' . implode('|', $this->except_urls) . '#';

        if ($this->isReading($request) || $this->tokensMatch($request) || preg_match($regex, $request->path()))
        {
            return $this->addCookieToResponse($request, $next($request));
        }

        throw new TokenMismatchException;
    }

}

And change in Kernel to point the new middleware :

protected $middleware = [

    ...

    'App\Http\Middleware\VerifyCsrfToken',
];
bestmomo
bestmomo
3 years ago (372,850 XP)

I think the easiest way is to create your own CSRF Middleware to manage exclusions.

trevorg

Wondered this myself. Right now I'm removing certain Middleware (CSRF included) altogether, and adding them back in for certain routes. But I feel like the opposite would be a better approach.

bashy
bashy
3 years ago (1,092,550 XP)
bestmomo
bestmomo
3 years ago (372,850 XP)

One way is to extend the VerifyCsrfToken and have an array of no csrf urls inside :

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Session\TokenMismatchException;

class VerifyCsrfToken extends \Illuminate\Foundation\Http\Middleware\VerifyCsrfToken {

    protected $except_urls = [
        'contact/create',
        'contact/update',
        ...
    ];

    public function handle($request, Closure $next)
    {
        $regex = '#' . implode('|', $this->except_urls) . '#';

        if ($this->isReading($request) || $this->tokensMatch($request) || preg_match($regex, $request->path()))
        {
            return $this->addCookieToResponse($request, $next($request));
        }

        throw new TokenMismatchException;
    }

}

And change in Kernel to point the new middleware :

protected $middleware = [

    ...

    'App\Http\Middleware\VerifyCsrfToken',
];
alexleonard

@bestmomo Awesome! Thanks for this detailed answer - has my API issues totally sorted :)

Much appreciated.

markvdputten

Indeed! Thanks @bestmomo really appreciate the detailed answer and it seems to fix the problems.

When loading in the latest dev copy of L5 though the CSRF implementation seem to have switched around again to be non default, a better approach if you asked my personal opinion.

bestmomo
bestmomo
3 years ago (372,850 XP)

@Mvdp are you sure CSRF is non default now ?

markvdputten

@bestmomo had another look and it was wrong in my mind... it looks like it stayed as it was. My bet!

E-dreamz_TP

This got me close, but still did not work. Here is my edit to get the image upload function to work with redactor wysiwyg.

//add an array of Routes to skip CSRF check
    private $openRoutes = ['redactorUpload'];
    public function handle($request, Closure $next)
    {
        if(in_array($request->path(), $this->openRoutes)){
            return $next($request);
        }else{
            return parent::handle($request, $next);
        }
    }

You can then add any route exceptions to the array that you need to skip the CSRF check.

pmall
pmall
2 years ago (580,645 XP)

What about moving the middleware to the route middleware in Kernel.php then :

class Kernel extends HttpKernel {

    /**
     * The application's global HTTP middleware stack.
     *
     * @var array
     */
    protected $middleware = [
        'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
        'Illuminate\Cookie\Middleware\EncryptCookies',
        'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
        'Illuminate\Session\Middleware\StartSession',
        'Illuminate\View\Middleware\ShareErrorsFromSession',
    ];
    /**
     * The application's route middleware.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => 'App\Http\Middleware\Authenticate',
        'auth.basic' => 'Illuminate\Auth\Middleware\AuthenticateWithBasicAuth',
        'guest' => 'App\Http\Middleware\RedirectIfAuthenticated',
        'csrf' => 'App\Http\Middleware\VerifyCsrfToken',
    ];

}
// Unprotected routes

$router->group(['middleware' => 'csrf'], function($router)
{
  // Protected routes
})

Anyway except if you are making a public api for external usage, there is no reason to skip csrf protection.

mshakeel

In Laravel 5.1, you can exclude URIs from CSRF protection by simply adding them to the $except property of the VerifyCsrfToken middleware:

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

Documentation: http://laravel.com/docs/5.1/routing#csrf-protection http://stackoverflow.com/questions/26992885/laravel-5-post-whithout-csrf-checking/32902801#32902801

rakmaster

That actually doesn't work. If you use the "except" variable and insert a member into the array, all Laravel will do is attempt to insert the token it finds in the session into the current request, then pass that request on. If there never was a token in the session, the request still fails.

I learned this when I installed Sleeping-Owl admin. I'm running a site where there is a user's area and an admin area. All of the user's area is secured by csrf. The admin is secured by sleeping-owl. If I try to upload a file while logged in as an admin (having never logged in as a user) the route fails no matter what. If I log into both the admin, and the front side the upload works fine. It had me confused until I spent an hour walking through every single step of the attempt.

Frustrating.

mdeclaire
consil
consil
1 year ago (12,110 XP)

@mdeclaire That is certainly the easiest technique. But do be aware, that App\Http\Middleware\VerifyCsrfToken lists the URLs that are excluded, not the routes. It uses the $request->is() method internally, so includes whatever wildcards that supports.

Personally, I don't like mixing route names and URL fragments all over the place. The controllers should not have to know what the URL formats are (laravel out of the box puts url paths in several places, which all need to be found and replaced with route names). Anyway, sorry to rant :-)

aliharis

You can also keep the route outside the group that make use of web middleware.

// Move route outside this group
Route::group(['middleware' => ['web']], function () {
});

Please sign in or create an account to participate in this conversation.