1

I'm thinking to CSRF protect all public AJAX requests that return JSON, because what's to prevent another site from spoofing the AJAX header and using the JSON as if it were a public API? I think CSRF protection is the best solution for this, however I'm concerned with the way Laravel handles this:

  1. Using laravel's CSRF filter, I notice in app/filters.php that it checks using Session:token, will this require every public visitor to have a session and put additional requirement on server RAM (as opposed to browsing without sessions).
  2. In the CSRF filter, Laravel checks Input::get('token'), but I may want to make POST ajax calls as well. Are POST requests not going to work?
  3. What if a visitor has a window open. They walk away for a bit...then return to perform an ajax request. This would be a problem and we would need to refresh the page, which would seem awkward for a public visitor (as opposed to logged in users, where we could just redirect to a login page).
  4. What if a visitor (or even logged in user) has 2 windows open? They walk away and let the session timeout. Then return and refresh one window (or login in again in one window), then go to the second window to perform an operation (only to find it doesn't work or they are forced to login again).

Can anyone address these concerns in Laravel's implementation of CSRF protection?

2
  • 1
    This is such a great question, and I'll be trying to solve this problem myself soon. Other related articles: stackoverflow.com/questions/31449434/… and jakzaprogramowac.pl/pytanie/…
    – Ryan
    Commented Apr 28, 2017 at 15:55
  • CSRF is server-side stateful by its nature. Sessions are one solution. A database might be another. But the bigger issue is: you will want the tokens to expire for securiry reasons. The longer they're exposed the more likely it is that they are stolen or guessed. You will have to face the issues that expiring state (be that only the token or an entire session) brings with it.
    – marstato
    Commented May 24, 2017 at 6:55

2 Answers 2

2
  1. Yes, all implementations I've seen for CSRF use sessions to store the token. This is so users can use the website in multiple tabs or windows without issuing multiple tokens (which effectively overwrites the previously valid token as only one token per user is tracked). I think you'll find the additional server requirements for using sessions is quite negligible.

  2. Post requests will work. The Input::get() function actually gets variables from $_GET and $_POST. To quote the documentation (http://laravel.com/docs/requests)

    You do not need to worry about the HTTP verb used for the request, as input is accessed in the same way for all verbs.

  3. A possible solution would be to pass back a new token in one of the json requests every time it expires. If you use this method and have normal (non ajax) forms on the same page you will have to use javascript to replace the token values in each of those forms.

  4. As the CSRF uses sessions to keep track of the token, and assuming you have solved problem 3, the second window should have no problem performing the operation as the tokens would be automatically refreshed on expiry.

0

Here Is an Answer To Your Question #3 about ajax and probably #4 too

For Laravel 5.4 in May 2017, I solved the problem this way:

In web.php:

Route::post('keep-token-alive', function() {
    //https://stackoverflow.com/q/31449434/470749
    return 'Token must have been valid, and the session expiration has been extended.'; 
});

In javascript in your view:

$(document).ready(function () {

    setInterval(keepTokenAlive, 1000 * 60 * 15); // every 15 mins

    function keepTokenAlive() {
        $.ajax({
            //https://stackoverflow.com/q/31449434/470749
            url: '/keep-token-alive', 
            type: 'post',
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        }).then(function (result) {
            console.log(new Date() + ' ' + result + ' ' + $('meta[name="csrf-token"]').attr('content'));
        });
    }

});

Note that you must not list 'keep-token-alive' in the exclusions within VerifyCsrfToken.php. As @ITDesigns.eu implied in a comment, it's important for this route to verify that there is a valid token currently and that it just needs to have its expiration extended.

See my more thorough answer here on StackOverflow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.