Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.net MVC AntiForgeryToken over AJAX

I am currently developing an MVC application in ASP.net. I am using AJAX.ActionLink to provide a delete link in a list of records, however this is very insecure. I have put this:

<AcceptVerbs(HttpVerbs.Post)>

Over the function to do the deleting, which stops the function being called simply by a URL. However, the other security hole that still exists is that if i were to make a basic html page with this content:

<form action="http://foo.com/user/delete/260" method="post">
<input type="submit" />
</form>

It would still be perfoming a post, but from a different location.

Is it possible to use the AntiForgeryToken with an AJAX ActionLink? If so, is this a secure approach? Are there more security holes i haven't realised?

like image 805
j82374823749 Avatar asked Aug 28 '09 10:08

j82374823749


2 Answers

Have a look at this blog post.

Say you have an Action method like this:

[AcceptVerbs(HttpVerbs.Post), ValidateAntiForgeryToken] public ActionResult DeleteAccount(int accountId) { // delete stuff }

And you call it via:

$.post('/home/DeleteAccount', { accountId: 1000 }, function() { alert('Account Deleted.'); });

Since the POST does not include the AntiForgeryToken, it will fail.

Fortunately, it doesn’t take much brainpower to fix this. All the client side component of AntiForgeryToken does is put the token in a basic hidden field. So, you just need to pull that data out and include it in your AJAX call.

var token = $('input[name=__RequestVerificationToken]').val();

$.post('/home/DeleteAccount', { accountId: 1000, '__RequestVerificationToken': token }, function() { alert('Account Deleted.'); });

Do note that if you have multiple forms on the page with multiple AntiForgeryTokens, you will have to specify which one you want in your jQuery selector. Another gotcha is if you are using jQuery’s serializeArray() function, you’ll have to add it a bit differently:

var formData = $('#myForm').serializeArray(); var token = $('input[name=__RequestVerificationToken]').val(); formData.push({ name: '__RequestVerificationToken', value: token });

$.post('/home/DeleteAccount', formData, function() { alert('Account Deleted.'); });

Update: The link has been fixed.

like image 188
RichardOD Avatar answered Sep 28 '22 03:09

RichardOD


You can use AntiForgeryToken with Ajax.ActionLink but you need to manually insert the AntiForgeryToken into the header of your request like so:

function GetAntiForgeryToken(){
   var tokenWindow = window;
   var tokenName = "__RequestVerificationToken";
   var tokenField = $(tokenWindow.document).find("input[type='hidden'][name='" +     tokenName +   "']");
   if (tokenField.length == 0) {return null;}
   else {
      return {
         name: tokenName,
         value: tokenField.val()
      };
   }
};

Then, we can use $.ajaxPrefilter to insert it into the header:

$.ajaxPrefilter(
   function (options, localOptions, jqXHR) {
      var token = GetAntiForgeryToken();
      jqXHR.setRequestHeader(token.name, token.value);
   }
);

I wrote a post about it here. Hope this helps!

like image 43
jjwhite01 Avatar answered Sep 28 '22 03:09

jjwhite01