Guarding against CSRF Attacks in ASP.NET MVC2

Alongside XSS (Cross Site Scripting) and SQL Injection, Cross-site Request Forgery (CSRF) attacks represent the three most common and dangerous vulnerabilities to common web applications today. CSRF attacks are probably the least well known but they are relatively easy to exploit and extremely and increasingly dangerous. For more information on CSRF attacks, see these posts by external link: Phil Haack and external link: Steve Sanderson.

The recognized solution for preventing CSRF attacks is to put a user-specific token as a hidden field inside your forms, then check that the right value was submitted. It's best to use a random value which you’ve stored in the visitor’s Session collection or into a Cookie (so an attacker can't guess the value).

ASP.NET MVC to the rescue

ASP.NET MVC provides an HTMLHelper called AntiForgeryToken(). When you call <%= Html.AntiForgeryToken() %> in a form on your page you will get a hidden input and a Cookie with a random string assigned.

Next, on your target Action you need to include [ValidateAntiForgeryToken], which handles the verification that the correct token was supplied.

Good, but we can do better

Using the AntiForgeryToken is actually quite an elegant solution, but adding [ValidateAntiForgeryToken] on all of your POST methods is not very DRY, and worse can be easily forgotten.

Let's see if we can make this easier on the program but moving from an "Opt-In" model of protection to an "Opt-Out" model.

Using AntiForgeryToken by default

In order to mandate the use of the AntiForgeryToken, we're going to create an ActionFilterAttribute which will do the anti-forgery validation on every POST request.

First, we need to create a way to Opt-Out of this behavior, so let's create a quick action filter called BypassAntiForgeryToken:

[AttributeUsage(AttributeTargets.Method, AllowMultiple=false)]
public class BypassAntiForgeryTokenAttribute : ActionFilterAttribute { }

Now we are ready to implement the main action filter which will force anti forgery validation on all post actions within any class it is defined on:

[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;
    }
}

The code above is pretty straight forward -- first we check to make sure this is a POST request, then we make sure there aren't any overriding *AntiForgeryTokenAttributes on the action being executed. If we have a candidate then we call the ValidateAntiForgeryTokenAttribute class directly and execute OnAuthorization() on the current authorization context.

Now on our base controller, you could use this new attribute to start protecting your site from CSRF vulnerabilities.

[UseAntiForgeryTokenOnPostByDefault]
public class ApplicationController : System.Web.Mvc.Controller { }
 
//Then for all of your controllers
public class HomeController : ApplicationController {}

What we accomplished

If your base controller has the new default anti-forgery token attribute on it, when you don't use <%= Html.AntiForgeryToken() %> in a form (or of course when an attacker doesn't supply one), the POST action will throw the descriptive error message "A required anti-forgery token was not supplied or was invalid". Attack foiled!

In summary, I think having an anti-CSRF policy by default is an effective way to protect your websites, and it turns out it is pretty easy to accomplish as well.

Enjoy!

32 Comments

  • Nice article, thanks!

  • your only missing the Html.BeginForm which besides form also outputs by default the AntiForgeryToken....then you have the whole package!



    Vladan

  • Good, simple and effective solutions for the problem.

  • nice post, really have informative information, thanks for publishing this post..

  • To me, I see no reason for this. You still have to remember to put the in the form. I guess if you forget, you will get an error since it will check for it by default... but in this case, I'd rather have it automatically added to my form as well. Also, I think I'd rather see each action explicitly have the [ValidateAntiForgeryToken] attribute, just so I (or another developer) know what's going on. Less DRY? Sure. Easier to understand? Yes!
    Adding the one extra attribute isn't enough to make me want to DRY it up. Even if it is on every POST. But, again, I'd rather have the option to just use it by default in the form and controller - this is how Rails works.

  • Very nice article! Thanks a lot!

  • What about the ajax call? it doesn't work when i use the AntiForgeryTokenAttribute

  • also I have same problem with jquery ajax. need your help. thanks.

  • nice post, really have informative information, thanks for publishing this post..

  • With these types of problems arising nowadays, it's good to know that it is being taken cared of and hopefully, the solution will be very helpful in addressing the problem.

  • I imagine I could potentially think of this a variety of ways. Thanks for submitting it.

  • I studied this post, but it is a little over my head. You must be one dude~!

  • I think your idea of using of having an anti-CSRF policy by default is a sound one. I will look into implementing this on my sites. I hope it's as easy as you make it sound!

  • Hello, i think that i saw you visited my website thus
    i came to go back the favor?.I am attempting to in finding
    issues to enhance my website!I guess its ok to make use of some of your ideas!

    !

  • I'm not sure where you're getting your info, but
    great topic. I needs to spend some time learning more or understanding more.
    Thanks for wonderful info I was looking for this info for my mission.

  • Quality articles or reviews is the secret to interest the viewers
    to visit the site, that's what this web site is providing.

  • Excellent publish we as well as thanks for the tips.
    Education is surely a tacky subject. However,
    is still on the list of major subjects of our time.
    I value your posting and look toward extra.

  • I've been teaching a category and we are looking at this topic in the next 7 days. I am directing my own student to consider your post once and for all information I have already been meaning to create something similar to this kind of in my web site and you've got given me an idea.

  • I want you in order to be able for you to help give thanks to for the time
    with this fantastic examine! My partner and my spouse and
    i actually definately enjoy every single bit of it and
    that i perhaps you have book marked to see new stuff of one's blog site essential examine blog site!

  • Hi there, You have done an incredible job.
    I will certainly digg it and personally recommend to my friends.

    I'm sure they'll be benefited from this site.

  • Hi there, I wish for to subscribe for this webpage to get hottest updates, so where can i do it please assist.

  • Hello, just wanted to say, I enjoyed this article.
    It was helpful. Keep on posting!

  • Yes! Finally something about burberry hommes.

  • My coder is trying to convince me to move to .net from PHP.
    I have always disliked the idea because of the costs.

    But he's tryiong none the less. I've been using WordPress on a number of websites for about a year and
    am worried about switching to another platform. I have
    heard good things about blogengine.net. Is there a way I can import all my wordpress content into it?
    Any kind of help would be greatly appreciated!

  • Hey this is kind of of off topic but I was wanting
    to know if blogs use WYSIWYG editors or if you have to manually code with HTML.
    I'm starting a blog soon but have no coding experience so I wanted to get advice from someone with experience. Any help would be greatly appreciated!

  • Heya i'm for the primary time here. I found this board and I find It truly useful & it helped me out a lot. I am hoping to give one thing again and aid others like you helped me.

  • What's up, of course this piece of writing is genuinely good and I have learned lot of things from it concerning blogging. thanks.

  • It's really very complex in this full of activity life to listen news on Television, thus I simply use the web for that purpose, and take the latest news.

  • Hello there! I recently desire to offer a huge browses upwards for that great info you have got the following about this submit.
    I'll probably be finding its way back in your website for additional soon.

  • wenchskimpy shaverfavouritismstoutfittingrep

  • I really enjoy basically reading through all your weblogs.
    Merely desired to inform you that you have people
    much at all as i am who enjoy your projects. Certainly an excellent publish.
    Less difficult on you! The information you have discussed is simply beneficial.

  • Itdoesn't have to be pretty; simply take hold of your a small note book plus record all you could perform toachieve an appartment abdomen. Very muchdirect botanical slimming soft gel ab operate: Individuals continue to have faith in "spot" decrease which workingyour abdominal muscles will probably burn off unwanted fat over them鈥?That may be consequently wrong! So as botanical slimming soft gel to help getsix-pack washboard abs, you should shed fat! Ab exercises shed very few caloriestherefore usually are not enough property off your own mid-section fat.

Comments have been disabled for this content.