PHP – CSRF Protection for Public AJAX Requests Returning JSON

ajaxlaravelPHP

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?

Best Answer

  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.