ASP MVC and XSRF

 
 
  • Gérald Barré

This post is part of the series 'Vulnerabilities'. Be sure to check out the rest of the blog posts of the series!

ASP MVC provides a straightforward way to protect against XSRF attacks. Just add the following line inside your form:

C#
@Html.AntiForgeryToken()

And the ValidateAntiForgeryToken attribute in the controller:

C#
[ValidateAntiForgeryToken]
public ActionResult Create(Model model)

This adds a hidden field to the page and a cookie. When the form is submitted, ASP.NET MVC validates both values:

HTML
<input name="__RequestVerificationToken" type="hidden" value="geGaItAfh7cil98mAt38y3ymsCsINWs1lH9cZY52lSjZ_bCU3vTgmS8IqONXJo6rLqjAI3pnf9IyUu2O9XGS_NsiSCzhbYy3wI4IeEX6WiQ1"/>

__RequestVerificationToken : 5qqXHEEfzDa_Jn7glEmgtOP586KRLlXOSpyznXvkMooZvQjI9fmDtQ9MH07eIt2vQhBcD44lpRLmMbjTFkkh6H081thqTpdfJ6F3VFLJ0Kw1

The problem is that it is easy to forget this attribute. To catch such omissions, you can write a unit test that checks every POST action method is decorated with the ValidateAntiForgeryToken attribute:

C#
[TestMethod]
public void PostMethodShouldBeDecoratedWithValidateAntiForgeryAttribute()
{
    var controllers = typeof(MvcApplication /* Could be any type from the project */).Assembly.DefinedTypes.Where(t => typeof(ControllerBase).IsAssignableFrom(t));
    foreach (var controller in controllers)
    {
        controller.Methods()
              .ThatReturn<ActionResult>()
              .ThatAreDecoratedWith<HttpPostAttribute>()
              .Should()
              .BeDecoratedWith<ValidateAntiForgeryTokenAttribute>("because all Actions with HttpPost require ValidateAntiForgeryToken");
    }
}

This test uses the FluentAssertions library. If you prefer not to use it, here is an equivalent test:

C#
[TestMethod]
public void PostMethodShouldBeDecoratedWithValidateAntiForgeryAttribute()
{
    var controllers = typeof(MvcApplication).Assembly.DefinedTypes.Where(t => typeof(ControllerBase).IsAssignableFrom(t));
    foreach (var controller in controllers)
    {
        foreach (MethodInfo method in controller.GetMethods())
        {
            if (method.GetCustomAttribute<HttpPostAttribute>() != null)
            {
                Assert.IsNotNull(method.GetCustomAttribute<ValidateAntiForgeryTokenAttribute>(), string.Format("Method {0}.{1} should be decorated with ValidateAntiForgeryTokenAttribute.", controller.Name, method.Name));
            }
        }
    }
}

Now you have no excuse to forget it.

Do you have a question or a suggestion about this post? Contact me!

Follow me:
Enjoy this blog?