AntiForgery.Validate() vs ValidateAntiForgeryToken

Chris Nevill picture Chris Nevill · Mar 18, 2014 · Viewed 9.2k times · Source

Does the method System.Web.Helpers.AntiForgery.Validate(); perform exactly the same function as the [ValidateAntiForgeryToken] decoration?

I'm thinking of changing my log out method too:

    [HttpPost]        
    public virtual ActionResult LogOff()        
    {
        if (User.Identity.Name != "")
        {
            System.Web.Helpers.AntiForgery.Validate();
            WebSecurity.Logout();
        }           

        return RedirectToAction(MVC.Account.Login());
    }

This would prevent an Anti Forgery exception being thrown when the system has already logged out due to the login expiring. I just want to be certain that AntiForgery.Validate() will perform the same task as ValidateAntiForgeryToken.

I was using an additional exception handler to catch this exception. The problem remained however that Elmah still logged this exception, and I'm getting to many messages.

Answer

Anthony Longano picture Anthony Longano · Mar 18, 2014

It would seem that both approaches would validate the AntiForgeryToken present in the form. I have checked the assemblies and the ValidateAntiForgeryTokenAttribute does call the AntiForgery.Validate method to do its validation. Both approaches will then throw a HttpValidateAntiForgeryException when validation fails. So the short answer to whether they perform the same task is Yes.

There is a subtle difference in the fact that the ValidateAntiForgeryTokenAttribute validates the token earlier in the MVC execution cycle-in the OnAuthorization method. This may make a difference in performance if you execute a resource intensive task in the controller action before doing your AntiForgeryToken.Validate() check.

Another thing to note is that you may be creating extra work for yourself (not to mention the possible security holes left when omitting it) by requiring that each HttpPost action have the following piece of code

if (User.Identity.Name != "")
{
    System.Web.Helpers.AntiForgery.Validate();
    WebSecurity.Logout();
}

By creating the following Attribute and decorating those post methods with it you will have your desired functionality and not be required to have the above code in every post action

using System;
using System.Web.Mvc;

[AttributeUsage( AttributeTargets.Method | AttributeTargets.Class , AllowMultiple = false , Inherited = true )]
public class ValidateOrSignOutAntiForgeryTokenAttribute : 
    FilterAttribute , 
    IAuthorizationFilter
{

    public void OnAuthorization( AuthorizationContext filterContext )
    {
        if( filterContext == null )
        {
            throw new ArgumentNullException( "filterContext" );
        }

        if( filterContext.HttpContext.User != null &&
            filterContext.HttpContext.User.Identity.Name != "" )
        {
            try
            {
                System.Web.Helpers.AntiForgery.Validate();
            }
            catch
            {
                WebSecurity.Logout();
                throw;
            }
        }
    }

}

One last thing, the exceptions are normal in the Validation of AntiForgery. This is because the AntiForgery.Validate method throws a HttpValidateAntiForgeryException when validation fails. As you see in the code above I have caught this Exception and re-thrown it after completing the Logout.