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.
Related
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.
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 need to render a Flask template but the ajax data is only accessible within the POST if statement and does not show when I call a get direct after a posted the data.
I have a working ajax here
$.ajax({
type: 'post',
url: "/query",
dataType: 'text',
data: JSON.stringify({hostname:hostname, bf_id:computerID}),
contentType: 'application/json;charset=UTF-8',
success: function () {
window.location.href = "/query";
}
});
});
The data is successfully posted and the redirect is working. But when the redirect calls the function to render the template, the posted ajax cannot be retrieved.
#app.route('/query', methods=["GET", "POST"])
def query():
hostname=""
if request.method == "POST":
#these values only exist in if statement
hostname = request.json['hostname']
bf_id = request.json['bf_id']
return render_template('query.html', hostname=hostname)
Am I using an incorrect work flow?
Am I using an incorrect work flow?
Yes.
You make the POST request with the data.
You get a response which does things with that data
You then make a GET request without the data
You get a response which can't do things with the data that it doesn't have
The point of Ajax is to make an HTTP request without loading a whole new page.
If you want to load a whole new page, then use a regular form submission without involving JavaScript at all.
I want to send a request to other domain like
http://ccv.viatelecom.com/services/?item=viacall&aid=XXXX&gid=XXXX&sid=XXXX&&num=XXXXXX
I have used Ajax request as below:
$.ajax({
type: "GET",
url:'http://ccv.viatelecom.com/services/?item=viacall&aid=XXXX&gid=XXXX&sid=XXXX&&num=XXXXXX',
success:function(data){
alert(data);
},
error:function(XMLHttpRequest, textStatus, errorThrown){
alert("XMLHttpRequest="+XMLHttpRequest.responseText+"\ntextStatus="+textStatus+"\nerrorThrown="+errorThrown);
}
});
but it does not go to success function and the alert erro is:
XMLHttpRequest=
textStatus=error
errorThrown=
if I write same url address bar it display message not in Ajax request.
Is this the correct way to send request or is there another way or something I am missing?
You can not perform a cross domain ajax call.
Work around for this
Method 1
JavaScript
Create a function
function getMyData(data) {
alert(data);
//Do the magic with your data
}
Server side
On server end wrap your data inside function syntax
getMyData("Enter your data here");
JavaScript
Then create a script tag and add a link to your cross-domain page
<script type="text/javascript"
src="cross ref url">
</script>
For reference: wikipedia
Method 2
Another option is Create a proxy on your domain. ie create a page in your domain which internally calls the cross-domain page and return the same data to your Ajax call.
I'm trying to use AJAX to send a query to Google Books and display the results on my website. I'm using JQuery to send the request and handling the response, like so:
var query = [formatted input from a form];
var URL = "http://books.google.com/books/feeds/volumes?q="+query+"&start-index=1&max-results=5";
$.ajax({
type: "GET",
url: URL,
dataType: "xml",
success: function(data, status){
alert(status);
}
});
Currently, I just have the script alerting "success" if a response is received. If I use my script to send that query to a local page for testing, this works just fine. But when I set the URL to the Google one listed above, as instructed on the Developer API page, I never see the alert. According to Firebug, I am receiving a response and a status of 200 ok as I should, but it's not getting to that "success" path. Does anyone know why?
Edit: I should add that if I follow the URL directly, to http://books.google.com etc. with some random q, it displays the feed XML with no problems, so the query is not the issue.
You can't make cross-domain requests using XMLHttpRequest under the standard browser security settings. One possible solution is to write a local proxy function (assuming you can create server-side code) that forwards the query to the external site, and then returns the response.
Edit: It looks like Google provides a JavaScript API as well. I would assume that they've crafted in such a way to avoid the cross-domain XHR issue.
http://code.google.com/apis/books/docs/js/devguide.html#execute
Edit: The JavaScript API for books was deprecated. While it's no longer practically useful, you can see the original referenced documentation text via the Wayback Machine archive: http://web.archive.org/web/20120414070427/http://code.google.com/apis/books/docs/js/devguide.html#execute
It's a cross-domain problem with ajax calls because browsers have a security model based on a domain policy.
if you don't wan to include the whole Google Books API, you can also use Google Ajax API with jsonp for cross-domain ajax calls.
Docs here:
http://code.google.com/apis/books/docs/js/jsondevguide.html#basic_query
jQuery example
var query = 'jquery';
var URL = 'https://ajax.googleapis.com/ajax/services/search/books?v=1.0&q=' + query;
$.ajax({
type: 'GET',
url: URL,
dataType: 'jsonp',
success: function( data, status ){
alert( data.responseData.results.length + ' results found!' );
},
error: function() {
alert( 'Something goes wrong!' );
}
});
Ciao!