Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

make sure each controller method has a ValidateAntiForgeryToken attribute?

Is there any way to centralize enforcement that every action method must have a "ValidateAntiForgeryToken" attribute? I'm thinking it would have to be done by extending one the "routing" classes.

Edit: Or maybe do some reflection at application startup?

like image 860
JoelFan Avatar asked Dec 21 '09 03:12

JoelFan


2 Answers

Yes. You can do this by creating your own BaseController that inherits the Mvc Controller, and overloads the OnAuthorization(). You want to make sure it is a POST event before enforcing it:

public abstract class MyBaseController : Controller
{
  protected override void OnAuthorization(AuthorizationContext filterContext)
  {
    //enforce anti-forgery stuff for HttpVerbs.Post
    if (String.Compare(filterContext.HttpContext.Request.HttpMethod,
          System.Net.WebRequestMethods.Http.Post, true) == 0)
    {
      var forgery = new ValidateAntiForgeryTokenAttribute();
      forgery.OnAuthorization(filterContext);
    }
    base.OnAuthorization(filterContext);
  }
}

Once you have that, make sure all of your controllers inherit from this MyBaseController (or whatever you call it). Or you can do it on each Controller if you like with the same code.

like image 124
eduncan911 Avatar answered Sep 22 '22 19:09

eduncan911


Sounds like you're trying to prevent "oops I forgot to set that" bugs. If so I think the best place to do this is with a custom ControllerActionInvoker.

Essentially what you want to do is stop MVC from even finding an action without a AntiForgery token:

public class MustHaveAntiForgeryActionInvoker : ControllerActionInvoker
{
    protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName)
    {
        var foundAction = base.FindAction(controllerContext, controllerDescriptor, actionName);

        if( foundAction.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), true ).Length == 0 )
            throw new InvalidOperationException("Can't find a secure action method to execute");

        return foundAction;
    }
}

Then in your controller, preferably your base controller:

ActionInvoker = new MustHaveAntiForgeryActionInvoker();

Just wanted to add that custom Controller base classes tend to get "thick" and imo its always best practice to use MVC's brilliant extensibility points to hook in the features you need where they belong.

Here is a good guide of most of MVC's extensibility points: http://codeclimber.net.nz/archive/2009/04/08/13-asp.net-mvc-extensibility-points-you-have-to-know.aspx

like image 29
John Farrell Avatar answered Sep 22 '22 19:09

John Farrell