I am building my first Laravel application and have a problem with the ajax request and specifically the CSRF verification.
I have followed all the steps in the documentation but it is not exactly doing what is said in there.
The App\Http\Middleware\VerifyCsrfToken middleware, which is included in the web middleware group by default, will automatically verify that the token in the request input matches the token stored in the session.
I have been manually concatenating 'test' to all CSRF tokens from the meta tag and the responses is still going through which it shouldn't of course.
Do I now have to manually Verify the CSRF token? If not what's the best practice to verify a token send in the headers of a jquery ajax post request through the controller?
I don't really understand what error that you encountered, but here's some Ajax setup and callin that i usually do.
//Setup header before callin ajax
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
//Ajax call update
$.ajax({
url: '/posts/1/update',
type: 'POST',
data: {
id: 123,
content: 'Abc123',
},
complete: function (response, xhr, settings) {
//Do something
}
});
You don't need to edit your VerifyCsrfToken middleware to make this work.
Related
I am working with CakePHP 3.6. I have a function that will return some data using AJAX call. This function will be called from any page of my website. It is like a button will be there and on clicking that button a modal will come with some data. Those data will come from AJAX call. So now the problem I am facing is with Csrf token. If I click from a page where a form is available then this AJAX call working perfect because there is a Csrf token available because of that form. But when I try clicking from a page where no form is available then AJAX is giving Csrf error. Because there is no Csrf added for that page.
This is how my button click and Ajax calling function looks like
$("#td-apt").on('click', function() {
getModalData();
$("#data-modal").modal('toggle');
});
function getModalData () {
$.ajax({
type: "POST",
url: "/function/Data",
headers: {
'X-CSRF-Token': $('input[name="_csrfToken"]').val()
},
dataType: "json",
success: function(data) {
console.log('success')
},
error: function() {
alert('Error');
}
});
}
So here are the things is it possible to generate Csrf token every time before calling this AJAX url. Or any other way to do this. Thanks
You can obtain the token from the request object in your view templates, for example in the layout to make it globally available:
<script>
var csrfToken = <?= json_encode($this->request->getParam('_csrfToken')) ?>;
// ...
</script>
You can then easily use it in your AJAX requests:
$.ajax({
headers: {
'X-CSRF-Token': csrfToken
},
// ...
});
Alternatively, if you already have some JS cookie parser at hand, you can obtain it from the cookie named csrfToken.
See also
Cookbook > Middleware > Cross Site Request Forgery (CSRF) Middleware
Cookbook > Middleware > CSRF Protection and AJAX Requests
I've got a problem. Every time I have to clear caches and cookies first and then the AJAX request can be requested successfully. Otherwise I will get 403 response from the server, which is Django RESTful framework.
This is what I request
$.ajax({
url: url_add,
type : 'PATCH',
dataType: 'json',
data: {
'followup_customer': note,
},
statusCode: {
200: function() {
window.location.reload();
}
},
});
You should add a correct HTTP header, containing CSRF token as described in django docs.
In twig i generate a csrf token ({{ csrf_token('my_intention') }}).
In Javascript i call a controller with ajax, in fact with the Fetch API (Ajax xmlHttpRequest tried too), POST request. Argument name containing the token passed in the request is 'token=abcdef...'.
AJAX:
var httpRequest = new XMLHttpRequest();
httpRequest.onreadystatechange = function (data) {
console.log(data);
};
httpRequest.open('POST', el.getAttribute("data-url"));
httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
httpRequest.send(.......);
Fetch API:
fetch(el.getAttribute('data-url'), {
method: 'post',
headers: {
"Content-type": "application/x-www-form-urlencoded; charset=UTF-8"
},
body: 'token=' + encodeURIComponent(el.getAttribute('data-token'))
}).then(data => data.text()).then(data => {...}
In the controller action called i get the token sent as data from the POST request. I check the token like this in the controller:
$token = $request->request->get('token');
if (!$this->isCsrfTokenValid('my_intention', $token)) {
throw new InvalidCsrfTokenException("error csrf 2");
}
But Symfony say the token is not valid.
I'm not sure but i think token is not found in session variable. In isTokenValid() $this->storage->hasToken($token->getId()) return false.
In the browser, if i call the url directly, it's ok.
In twig i set the url to call in a data attribute like this data-url="{{ path('_check', {'id': transaction.id}) }}", then i read this data attribute from javascript and pass it to ajax/fetch function.
I tried ajax with jQuery $.post(... and it works. The only difference is Cookie:PHPSESSID... in the request header with jQuery not on my original code.
I don't understand, what is wrong with my code ?
Symfony 3.1.3
EDIT: resolved: i didn't pass credentials in headers request, so, no way for Symfony to find session and check token:
fetch(el.getAttribute('data-url'), {
method: 'post',
headers: {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
"X-Requested-With": "XMLHttpRequest"
},
body: 'token=' + el.getAttribute('data-token'),
credentials: 'include'
}).then(data => data.text()).then(data => {
Even if you found an answer to your issue, I recommend you to take a look at this bundle which handles the token verification based on a Cookie which is defined server-side and that you should pass in each asynchronous request.
https://github.com/dunglas/DunglasAngularCsrfBundle
I'm using Laravel 5.2 for my web application and I have a page with multiple ajax requests by the same event. In $.ajax, I set async: true, Sometimes it shows CSRF token Mismatch error and redirect to login page. However when I set Async: false in ajax, it works fine but it takes lots of time.
Please help me so that it does not show token mismatch error.
in your form create one hidden filed name _token you can use this helper method to generate field
{!! csrf_field() !!}
in javascript you have to fetch this field value
var token = $( "input[name='_token']" ).val();
$.ajax({
method: "POST",
url: "some.php",
data: { name: "John", location: "Boston",_token:token }
});
another way create hidden a span or div add data attribute to it
<div id="token" data-token="{{ csrf_token() }}"></div>
fetch in javascript data value
var token = $( "#token" ).data('token');
$.ajax({
method: "POST",
url: "some.php",
data: { name: "John", location: "Boston",_token:token }
});
You said you use
$.ajaxSetup({ headers: { 'X-CSRF-Token' : $('meta[name=_token]').attr('content') } });
Maybe somewhere headers in request overrides, try to change it on
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader('X-CSRF-Token', $('meta[name=_token]').attr('content') );
}
});
Please modify your url variable like so :
url: '/my-route'+'?_token=' + '{{ csrf_token() }}',
I think it is not possible to cater this scenario (handing concurrent async requests) in session based CSRF implementation.
Consider 2 async request, r1 and r2:
both are sync and hit at the same time for same session on the CSRF Filter.
r1 changes the CSRF token value which is stored for session id and completes its implementation.
whereas r2 gets TOKEN_MISMATCH since, it has the same old token in the request header which is now get expired by r1 request completion.
So, for r2, CSRF filter will raise error.
I have enabled Codeigniter's CSRF protection on my site that uses AJAX to submit a user form and handles some other user interaction which require data submission via AJAX. As a result I came up against the "action not allowed" server side error. I quickly worked out that only the data my javascript collected and submitted via AJAX was passed to the server and as a result the CSRF code was not being sent.
The generated token tag looks like:
<input type="hidden" name="csrf_test_name" value="dsflkabsdf888ads888XXXXXX" />
So it seems to me the simplest way to submit the token to the server for verification is using a jQuery selector on csrf_test_name to get the value and then adding this to my post data for the server to verify. As per the code below:
//get CSRF token
var csrf = $('[name="csrf_test_name"]').val();
//build the form data array
var form_data = {
csrf_test_name: csrf,
... ... ...
... ... ...
}
//send the form data to the server so it can be stored
$.ajax({
type: "POST",
data: form_data,
url: ...,
dataType: "html",
success: function(msg){
... ... ...
}//end success
});//end ajax
I have followed this procedure for every ajax submission that sends data to the server and the server side error is fixed and everything works fine.
To test this I have hard coded in an incorrect CSRF token and the server detects the inconsistency and returns an erro code 500 so on the surface this works.
My question is this, is this a safe way to do this and is there an expected best practice to follow? I have done some google searching on this and it seems all the other methods are more complex and I am wondering if my way creates an attack vector that I can't see/workout.
I like to add it to the Ajax setup. Set it once and have it automatically add it to the post data for all of your requests.
$.ajaxSetup({
data: {
csrf_test_name: $("input[name='csrf_test_name']").val()
}
});
an easier method is to pass that csrf to $.ajaxSetup() that way it's included with any $.ajax() request afterward.
var csrf = $('input[name="csrf_test_name"]').val();
var data = {};
data[CSRF] = csrf;
$.ajaxSetup({ 'data': data });
then no need to include data: { csrf_test_name: 'xxx', ... } in requests after setup.