views:

593

answers:

3

I know how to use MVC's AntiForgeryToken attribute and it's associated HTML helper to help XSRF-secure my application's form POSTs.

Can something similar can be done for JsonResults that implement GET?

For instance, my View contains an onSubmit jQuery call like such:

$.getJSON("/allowActivity/YesOrNo/" + someFormValue, "{}", function(data) {
  if(data.Allow) {
    //Do something.
  }
});

I want to make certain that this JsonResult is only callable from the intended page.

EDIT:

I found this post about a similar question, with no concrete answer.

What is the easiest way to ensure that my GET(non-destructive) URL is consumed only by an AJAX call from my own page?

A: 

You can do something similar as the anti XSRF methods. Just generate some ID insert it into the javascript and when the user calls your JSON url, have that url include the generated ID and check if it is there.

A defense against XSRF is also using the sessionID as key, this doesn't stop the user executing it from another website for his own account though.

Some hash based on the session and time might do the trick. Ofcourse if the user copies the value from the JS, he can still execute it from another location, but you can have that value expire every x minutes. Another option is to set a cookie with JS and read it serverside.

Hope this gives you some ideas to get you started.

Tomh
+8  A: 

You may use the AntiForgeryToken combined with some custom logic. The creation of the AntiForgery token on the server is the same, but by default the value is not included in your XmlHttpRequest.

The value of this token is in the HTTP only cookie "__RequestVerificationToken" and should also be in the form data posted to the server. So include a key/value pair in your XmlHttpRequest and use the ValidateAntiForgeryToken - attribute on your controller

EDIT:

Today I tried using the AntiForgeryToken for Ajax requests myself and it works fine. Just use the following javascript:

$.post('my_url',  $.getAntiForgeryTokenString(), function() { ... });

$.getAntiForgeryTokenString = function() {
    return $(document.getElementsByName("__RequestVerificationToken")).fieldSerialize();
};

On the server side you don't have to change your code - just use the ValidateAntiForgeryToken- attribute for your action.

Hope this helps

ollifant
How would you integrate the __RequestVerificationToken value with the $.getJSON or $.ajax call? Remember, this is a GET request.
Peter J
Read "Disclosure of Token in URL" from http://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet" If sensitive server-side actions are guaranteed to only ever respond to POST requests, then there is no need to include the token in GET requests" The key is to make sure your GET doesn't modify data. Otherwise, you don't need to protect GET requests
Mark J Miller
+1  A: 

First of all why not to use $.post(url, data, callback, 'json') instead of getJSON? And as kleolb02 said, you may add value from the cookie to the post data using cookie plugin - {__RequestVerificationToken: $.cookie('__RequestVerificationToken')}

zihotki
That sounds good. I was hoping to avoid POST for such a simple ajax call, but I certainly will if it's the only way to secure it.
Peter J
You should use post to update some data on the server. This is a common scenario. And as far as I remember AntiForgeryToken's are working only with post requests (they looks for a value in FormCollection only).
zihotki
This is not an update, it is a simple "get". I would simply like to restrict the URL's consumption to my own page's AJAX calls.
Peter J
Sorry, this is not possible to restrict it. You may check referrer url and some specific cookies but they can be easily emulated. You can only restrict access to url to not authorized users. For this you can use standard login authorization.
zihotki