Thursday, November 24, 2011

Protecting against CSRF in MVC 3

It is important to protect your customers and other users of your website against CSRF attacks. To do this in ASP.NET MVC 3, you would normally use the ValidateAntiForgeryTokenAttribute. The test below will ensure that all appropriate actions on all controllers have this protection.
[TestMethod]
public void All_post_actions_validate_anti_forgery_tokens()
{
    var modelController = typeof(MyController);  //this can be any one of your controllers in this particular area
    var allControllers = modelController.Assembly.GetTypes().Where(t => t.Namespace == modelController.Namespace && t.Name.EndsWith("Controller", StringComparison.OrdinalIgnoreCase));
    foreach (var controller in allControllers)
    {
        AssertControllerValidatesAntiForgeryToken(controller);
    }
}

static void AssertControllerValidatesAntiForgeryToken(Type controller)
{
    Console.WriteLine("Checking " + controller.Name);
    var violations = (
        from method in controller.GetMethods()
        let attributes = method.GetCustomAttributes(true)
        let parameters = method.GetParameters()
        let isProperty = !method.Name.StartsWith("set_", StringComparison.OrdinalIgnoreCase) && !method.Name.StartsWith("get_", StringComparison.OrdinalIgnoreCase)
        let isPostMethod = parameters.Length != 0 && (!attributes.Any(a => a is ActionMethodSelectorAttribute) || attributes.Any(a => a is HttpPostAttribute))
        let noAntiForgeryToken = !attributes.Any(a => a is ValidateAntiForgeryTokenAttribute)
        let excludedMethods = typeof(ControllerBase).GetMethods().Select(m => m.Name)
        let isExcludedMethod = excludedMethods.Contains(method.Name)
        where isProperty && isPostMethod && noAntiForgeryToken && !isExcludedMethod
        select method.Name).ToArray();

    foreach (var violation in violations)
        Console.WriteLine("Failed: {0}/{1}", controller.Name, violation);

    Assert.AreEqual(0, violations.Count());
}         

0 comments:

Post a Comment