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:

[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:

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:

[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)!

Flattr
blog comments powered by Disqus