Updated Anti-XSRF Validation for ASP.NET MVC 4 RC

In our project, we’ve been using Phil Haack’s method for preventing cross-site request forgeries for JSON posts by inserting the request verification token as a header in the request, and then using a custom ValidateJsonAntiForgeryToken attribute to validate it. And it’s been working just fine.

However, with the recent release of ASP.NET 4 MVC RC, it didn’t work anymore. To my initial dismay, it didn’t even compile anymore. Turns out that the method, AntiForgery.Validate(HttpContextBase httpContext, string salt) , that hade been used to validate the tokens is now obsolete.

However, this turned out to be a good thing, as the MVC developers have made it easier to configure the anti-XSRF validation. You can now provide the tokens directly to the Validate method, and thus there is no need to create a wrapper for the HttpContext and the HttpRequest anymore.

Instead, you can just call the validate method with the proper tokens directly from your attribute:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,
AllowMultiple = false, Inherited = true)]
public sealed class ValidateJsonAntiForgeryTokenAttribute
: FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}

var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
}
}

And, just to make this post complete, in case the original post is removed, this is the javascript required to add the header to the request:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
postJsonWithVerificationToken: function (options) {
var token = $('input[name=""__RequestVerificationToken""]').val();
var headers = {};
headers['__RequestVerificationToken'] = token;

$.ajax({
cache: false,
dataType: 'json',
type: 'POST',
headers: headers,
data: options.jsonData,
contentType: 'application/json; charset=utf-8',
url: options.url,
success: options.onSuccess,
error: options.onError
});
}

Finally, you just use it as you would the standard ValidateAntiForgeryToken attribute, by decorating your action method like this:

1
2
3
4
[HttpPost, ValidateJsonAntiForgeryToken]
public ActionResult DoSomething(Foo foo) {
//Do something
}

And in your form, you just call Html.AntiForgeryToken(), just as you would for a normal form post.

A lot cleaner than the previous haack (although it was very clever)!