I have implemented in my app the mitigation to CSRF attacks following the informations that I have read on some blog post around the internet. In particular these post have
Okay lots of posts here, none of them helped me, days and days of google, and still no further I got to the point the wr-writing the whole app from scratch, and then I noticed this little nugget in my Web.confg
<httpCookies requireSSL="false" domain="*.localLookup.net"/>
Now I don't know why I added it however I have since noticed, its ignored in debug mode and not in a production mode (IE Installed to IIS Somewhere)
For me the solution was one of 2 options, since I don't remember why I added it I cant be sure other things don't depend on it, and second the domain name must be all lower case and a TLD not like ive done in *.localLookup.net
Maybe it helps maybe it don't. I hope it does help someone
I was just implementing this actual problem in my current project. i did it for all ajax-POSTs that needed an authenticated user.
First off i decided to hook my jquery ajax calls so i do not to repeat myself too often. this javascript snippet ensures all ajax (post) calls will add my request validation token to the request. Note: the name __RequestVerificationToken is used by the .Net framework so i can utilize the standard Anti-CSRF features as shown below.
$(document).ready(function () {
var securityToken = $('[name=__RequestVerificationToken]').val();
$('body').bind('ajaxSend', function (elm, xhr, s) {
if (s.type == 'POST' && typeof securityToken != 'undefined') {
if (s.data.length > 0) {
s.data += "&__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
else {
s.data = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
}
}
});
});
In your Views where you need the token to be available to the above javascript just use the common HTML-Helper. You can basically add this code whereever you want. I placed it within a if(Request.IsAuthenticated) statement:
@Html.AntiForgeryToken() // you can provide a string as salt when needed which needs to match the one on the controller
In your controller simply use the standard ASP.Net MVC Anti-CSRF mechanism. I did it like this (though i actually used Salt).
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public JsonResult SomeMethod(string param)
{
// do something
return Json(true);
}
With Firebug or a similar tool you can easily see how your POST requests now have a __RequestVerificationToken parameter appended.
I'm using a ajax post to run a delete method (happens to be from a visjs timeline but that's not relelvant). This is what I sis:
This is my Index.cshtml
@Scripts.Render("~/bundles/schedule")
@Styles.Render("~/bundles/visjs")
@Html.AntiForgeryToken()
<!-- div to attach schedule to -->
<div id='schedule'></div>
<!-- div to attach popups to -->
<div id='dialog-popup'></div>
All I added here was @Html.AntiForgeryToken()
to make the token appear in the page
Then in my ajax post I used:
$.ajax(
{
type: 'POST',
url: '/ScheduleWorks/Delete/' + item.id,
data: {
'__RequestVerificationToken':
$("input[name='__RequestVerificationToken']").val()
}
}
);
Which adds the token value, scraped off the page, to the fields posted
Before this I tried putting the value in the headers but I got the same error
Feel free to post improvements. This certainly seems to be a simple approach that I can understand
AntiforgeryToken is still a pain, none of the examples above worked word for word for me. Too many for's there. So I combined them all. Need a @Html.AntiforgeryToken in a form hanging around iirc
Solved as so:
function Forgizzle(eggs) {
eggs.__RequestVerificationToken = $($("input[name=__RequestVerificationToken]")[0]).val();
return eggs;
}
$.ajax({
url: url,
type: 'post',
data: Forgizzle({ id: id, sweets: milkway }),
});
When in doubt, add more $ signs
I think all you have to do is ensure that the "__RequestVerificationToken" input is included in the POST request. The other half of the information (i.e. the token in the user's cookie) is already sent automatically with an AJAX POST request.
E.g.,
$("a.markAsDone").click(function (event) {
event.preventDefault();
$.ajax({
type: "post",
dataType: "html",
url: $(this).attr("rel"),
data: {
"__RequestVerificationToken":
$("input[name=__RequestVerificationToken]").val()
},
success: function (response) {
// ....
}
});
});
Further to my comment against @JBall's answer that helped me along the way, this is the final answer that works for me. I'm using MVC and Razor and I'm submitting a form using jQuery AJAX so I can update a partial view with some new results and I didn't want to do a complete postback (and page flicker).
Add the @Html.AntiForgeryToken()
inside the form as usual.
My AJAX submission button code (i.e. an onclick event) is:
//User clicks the SUBMIT button
$("#btnSubmit").click(function (event) {
//prevent this button submitting the form as we will do that via AJAX
event.preventDefault();
//Validate the form first
if (!$('#searchForm').validate().form()) {
alert("Please correct the errors");
return false;
}
//Get the entire form's data - including the antiforgerytoken
var allFormData = $("#searchForm").serialize();
// The actual POST can now take place with a validated form
$.ajax({
type: "POST",
async: false,
url: "/Home/SearchAjax",
data: allFormData,
dataType: "html",
success: function (data) {
$('#gridView').html(data);
$('#TestGrid').jqGrid('setGridParam', { url: '@Url.Action("GetDetails", "Home", Model)', datatype: "json", page: 1 }).trigger('reloadGrid');
}
});
I've left the "success" action in as it shows how the partial view is being updated that contains an MvcJqGrid and how it's being refreshed (very powerful jqGrid grid and this is a brilliant MVC wrapper for it).
My controller method looks like this:
//Ajax SUBMIT method
[ValidateAntiForgeryToken]
public ActionResult SearchAjax(EstateOutlet_D model)
{
return View("_Grid", model);
}
I have to admit to not being a fan of POSTing an entire form's data as a Model but if you need to do it then this is one way that works. MVC just makes the data binding too easy so rather than subitting 16 individual values (or a weakly-typed FormCollection) this is OK, I guess. If you know better please let me know as I want to produce robust MVC C# code.