Sunday, June 23, 2013

Responsible use of the ASP.NET MVC AntiForgeryToken

June 23, 2013 Posted by Jason Irwin , , No comments

The use of anti-forgery tokens is a necessary safeguard against cross-site request forgery attacks. The ASP.NET MVC framework provides easy-to-use security mechanisms right out of the box, but unfortunately these are opt-in rather than opt-out and are easy to miss/forget. For a non-trivial website it is difficult to guarantee tokens are supplied and checked in all form submissions and AJAX posts. This is how I do it.
Note: Web security is a tricky business and I do not consider myself a security expert. Use the information in this post at your own risk.

1. Use the ValidateJsonAntiForgeryToken attribute for AJAX calls

There's a nice post by Johan Driessen on anti-XSRF validation with newer versions of the .NET framework. I use Johan's ValidateJsonAntiForgeryToken attribute to great effect. In summary, Johan's attribute should be applied to actions invoked via AJAX calls. Check out his blog post - it explains everything in detail.

2. Ensure all AJAX posts contain a verification token

In my root layout file (master page) I use the following code to set expectations for jQuery AJAX calls. Prior to executing a call, the request verification token is read from the current page (Note: a Html.AntiForgeryToken call needs to be in place in every page which will utilize ajax posts) and passed into the request header. This saves me from needing to specify a token every time I create an AJAX call. (This can easily be modified to only send the token for desired HTTP verbs)
Loading ....

3. Ensure all POST methods have validation attributes applied

It's very easy to forget to apply the ValidateAntiForgeryToken attribute when developing new actions. I have a little unit test that I run to ensure that all post methods have either ValidateAntiForgeryToken or ValidateJsonAntiForgeryToken applied. The test fails and prints a list of offender actions when appropriate. This is a lifesaver when, inevitably, I'm developing some new functionality in a rush and haven't given security its appropriate consideration (hopefully this is a rarity).
Loading ....
Hopefully this saves somebody some time. Let me know if there are any considerations that I have missed, or if you know of a more elegant method of achieving the same!