CSRF protection difference: Laravel 4.x, 5.0 and 5.1

For those who work with different Laravel versions on different projects, it’s useful to know the difference of CSRF logic – it changed a little from 4.x to 5.x.

Laravel 4.2

In version 4.x we had filters. So we could add something into app/filters.php file, and one of pre-created filters was CSRF – right at the end of the file:

Route::filter('csrf', function()
{
	if (Session::token() !== Input::get('_token'))
	{
		throw new Illuminate\Session\TokenMismatchException;
	}
});

And then we can use that filter on whichever routes we prefer, usually on POST calls:

Route::post('register', array('before' => 'csrf', function()
{
    return 'You gave a valid CSRF token!';
}));

And, of course, we shouldn’t forget to include the token itself in our forms:

<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">

So that was 4.x. Pretty straightforward, huh?

Laravel 5.0

Version 5.0 (which, actually, originally was planned as 4.3) introduced Middleware instead of filters. And there was a particular set of Middleware classes that were loaded by default. Including CSRF.

app/Http/Kernel.php – the last line of the array:

class Kernel extends HttpKernel {

	protected $middleware = [
		'Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode',
		'Illuminate\Cookie\Middleware\EncryptCookies',
		'Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse',
		'Illuminate\Session\Middleware\StartSession',
		'Illuminate\View\Middleware\ShareErrorsFromSession',
		'Illuminate\Foundation\Http\Middleware\VerifyCsrfToken',
	];

This VerifyCsrfToken class was included in default $middleware which, in essence, meant that all POST calls are csrf-protected by default. And that became a problem.

See, not every POST request comes from a form. There are external calls for some API function, AJAX requests and various other cases. So people started to rant and search for the answer how to remove CSRF from default middleware. Of course, the obvious answer is to not include it in $middleware array, and add it whenever needed, like in good old Laravel 4.

Laravel 5.1 – problem solved

So, Taylor saw the problem and changed the logic in 5.1 version. Actually, there are several new things here:

1. You can use function csrf_field() to generate the whole input instead of just token.
So instead of:

<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">

You can just write:

{!! csrf_field() !!}

2. There is still VerifyCsrfToken present in $middleware array:

    protected $middleware = [
        \Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
    ];

3. BUT: you can exclude it from certain URLs you want. You can to it directly in app/Http/Middleware/VerifyCsrfToken.php class, by using property $except:

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

Notice that you can use a * (star) symbol to specify the rule, and this rule describes URLs, not routes.

So that’s a brief history of CSRF in Laravel so far. Would you add more “tricks” that you use for CSRF protection?

Like our articles?
Check out our Laravel online courses!

6 COMMENTS

  1. Personally the ‘except’ functionality in 5.1 is a really bad idea, it removes this layer of security which opens a potential hole in your app. Dumbing down security to get around what is a relatively trivial thing to configure shouldn’t be encouraged.

    To retrieve the key for ajax requests you should read the XSRF-TOKEN cookie which is set in 5.0 & 5.1. You should then setup the X-XSRF-TOKEN header with this value. This takes from a relatively common practice with rails

    (function($) {
    $.ajaxSetup({
    headers: {
    ‘X-CSRF-Token’: Cookies.get(‘XSRF-TOKEN’);
    }
    });
    })(jQuery);

  2. I have an existing form CSRF, but when hosting an error occurs TokenMismatchException VerifyCsrfToken.php in line 67. earlier on localhost running normally no error. Please help

LEAVE A REPLY

Please enter your comment!
Please enter your name here