I recently migrated to Laravel 5, and now CSRF check is on every post submission. I thought about removing it but I want to follow the best practices, so I'll keep it that way.
On the other hand, I'm problems submitting ajax requests.. my page has multiple forms and some submissions are not even from forms, just plain ajax calls. My idea is to have one single hidden "token" input on the page and attach it to every submission. Are there any drawbacks on having that universal single token input?
Also, how can I output the token? Would it be ok to just create a hidden input on the page footer?
回答1:
I don't see any drawbacks. You can easily create a global token field in your layout file:
Or if you use the form builder:
{!!Form::token()!!}
In jQuery you could use something like this to attach the token to every request.
回答2:
There is a helper to add the form token inside forms. You can just use
{!! csrf_field()!!}
inside the forms. It will add the hidden input and the token.
回答3:
Here are some excerpts of how I got my CSRF working for all the different scenarios in my jQuery Mobile application that I recently upgraded to use Laravel 5:
I added an encrypted csrf token in a variable that will be passed to my views in my main base controller: app\Http\Controllers\MyController.php
But, the key (for my setup at least) was the addition of the check for the XSRF-TOKEN cookie in my custom VerifyCsrfToken middleware: app\Http\Middleware\VerifyCsrfToken.php:
Before I added that, just about all of my AJAX POSTs (including form submissions and lazyloading listviews) were failing due to a TokenMismatchException.
EDIT: On second thought, I'm not sure how much sense it makes to compare the session token with the one set in the cookie (which would have come from the session token in the first place right?). That may have just been bypassing the security of it all.
I think my main issue was with the jquery snippet above which was supposed to be adding the X-XSRF-TOKEN header to every ajax request. That wasn't working for me in my in jQuery Mobile app (specifically, in my lazyloader plugin) until I added some options for the plugin itself. I added a new default selector csrf (which would be meta[name="_token"] in this case) and a new default setting csrfHeaderKey (which would be X-XSRF-TOKEN in this case). Basically, during initialization of the plugin, a new _headers property is initialized with the CSRF token if one is locatable by the csrf selector (default or user-defined). Then, in the 3 different places where an ajax POST can be fired off (when resetting session variables or when lazyloading a listview) the headers option of $.ajax is set with whatever is in _headers.
Anyway, since the X-XSRF-TOKEN received on the server-side comes from the encrypted meta _token, I think the CSRF protection is now working as it should.
My app\Http\Middleware\VerifyCsrfToken.php now looks like this (which is essentially back to the default implementation provided by Laravel 5 - LOL):
You can use something like this at the bottom of the page:
$('form').append('{{csrf_field()}}');
This will append a hidden input to all your forms:
And for all your AJAX requests:
$.ajaxSetup({ beforeSend:function(xhr, settings){//////////// Only for your domainif(settings.url.indexOf(document.domain)>=0){ xhr.setRequestHeader("X-CSRF-Token","{{csrf_token()}}");}