How can I write an ActionFilter that ensures that AntiForgeryTokens are used for every Post operation?

I want to use AntiForgeryTokens for every HttpPost action using an ActionFilter that resides in a controller named ControllerBase , which inherits every other controller.

I want to do this by creating an ActionFilter that inherits from the ValidateAntiForgeryToken , which takes an argument that tells it which HTTP verbs itself refers to. Then I want to apply this filter to ControllerBase to make sure that the AntiForgeryToken checked for AntiForgeryToken POST operation on the whole site.

I was looking to use this solution , but

  • AuthorizationContext Constructor (ControllerContext) is an outdated constructor, and I'm not sure how to rebuild the code using the recommended AuthorizationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor) .

  • By default, it does not use AntiForgeryToken, since I get the following error: A required anti-forgery token was not supplied or was invalid after each post action.

How can I rewrite my ActionFilter to meet current non-obsolete standards and correctly use the anti-fake token for each [HttpPost] verb?

Should I include an anti-fake token in each form (I think I'm doing)? (unlike the fact that it is automatically generated - don't laugh, I'm curious) Update: As indicated in the comments; Yes, it needs to be done with each form.

Here is the code from my ControllerBase for reference:

 [UseAntiForgeryTokenOnPostByDefault] public class ControllerBase : Controller { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] public class BypassAntiForgeryTokenAttribute : ActionFilterAttribute { } [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] public class UseAntiForgeryTokenOnPostByDefault : ActionFilterAttribute { public override void OnActionExecuting(ActionExecutingContext filterContext) { if (ShouldValidateAntiForgeryTokenManually(filterContext)) { var authorizationContext = new AuthorizationContext(filterContext.Controller.ControllerContext); //Use the authorization of the anti forgery token, //which can't be inhereted from because it is sealed new ValidateAntiForgeryTokenAttribute().OnAuthorization(authorizationContext); } base.OnActionExecuting(filterContext); } /// <summary> /// We should validate the anti forgery token manually if the following criteria are met: /// 1. The http method must be POST /// 2. There is not an existing [ValidateAntiForgeryToken] attribute on the action /// 3. There is no [BypassAntiForgeryToken] attribute on the action /// </summary> private static bool ShouldValidateAntiForgeryTokenManually(ActionExecutingContext filterContext) { var httpMethod = filterContext.HttpContext.Request.HttpMethod; //1. The http method must be POST if (httpMethod != "POST") return false; // 2. There is not an existing anti forgery token attribute on the action var antiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (ValidateAntiForgeryTokenAttribute), false); if (antiForgeryAttributes.Length > 0) return false; // 3. There is no [BypassAntiForgeryToken] attribute on the action var ignoreAntiForgeryAttributes = filterContext.ActionDescriptor.GetCustomAttributes(typeof (BypassAntiForgeryTokenAttribute), false); if (ignoreAntiForgeryAttributes.Length > 0) return false; return true; } } } 
+8
asp.net-mvc asp.net-mvc-3 antiforgerytoken action-filter
source share
2 answers

You do not need to instantiate any AuthorizationContext or call the OnAuthorization method, simply:

 if (ShouldValidateAntiForgeryTokenManually(filterContext)) { AntiForgery.Validate(filterContext.HttpContext, null); } 
+1
source share

I used the following approach:

 public class SkipCSRFCheckAttribute : Attribute { } public class AntiForgeryTokenFilter : IAuthorizationFilter { public void OnAuthorization(AuthorizationContext filterContext) { if (IsHttpPostRequest(filterContext) && !SkipCsrfCheck(filterContext)) AntiForgery.Validate(); } private static bool IsHttpPostRequest(AuthorizationContext filterContext) { return filterContext.RequestContext.HttpContext.Request.HttpMethod == HttpMethod.Post.ToString(); } private static bool SkipCsrfCheck(AuthorizationContext filterContext) { return filterContext.ActionDescriptor.GetCustomAttributes(typeof (SkipCSRFCheck), false).Any(); } } 

This allows us to disable it in each case using the SkipCSRFCheck attribute, and then register it as a global filter in Application_Start:

GlobalFilters.Filters.Add (new AntiForgeryTokenFilter ());

+7
source share

All Articles