How to Handle the MVC HttpAntiForgeryException
When developing forms for websites it is good practice to guard against cross site request forgery attacks. In MVC it is straightforward to do this using the AntiForgeryToken() helper method and the ValidateAntiForgeryToken attribute (as explained by Steve Sanderson). However a side effect of this is that an HttpAntiForgeryException like this will be thrown whenever a forgery attack is prevented:
System.Web.Mvc.HttpAntiForgeryException: A required anti-forgery token was not supplied or was invalid.
This is not generally a problem unless the site has been setup to notify you of any exceptions by email. Then you may find that your inbox quickly fills up with spam error reports and I think there is already quite enough spam in the world! The fix for this is to catch the exception before it makes it out of the application and into your inbox. The exception can be caught by adding the HandleError attribute to the controller class declaration as shown below:
[HandleError(ExceptionType=typeof(HttpAntiForgeryException), View="Unauthorised")]
public class MyController : Controller
{
...
public ActionResult Unauthorised()
{
return View("Unauthorised");
}
}
Once the attribute has been added the Unauthorised view should be shown if a forgery attempt is intercepted. However in my case a different exception of the type shown below was thrown instead:
The model item passed into the dictionary is of type ‘System.Web.Mvc.HandleErrorInfo’ but this dictionary requires a model item of type ‘Core.Web.ViewModels.ISomeViewModel’.
This exception is thrown because (as described in this work item on the MVC issue tracker) the default view model has been replaced by a HandleErrorInfo object and our master page is trying to access properties in the normal view model. So the straightforward fix for this is to remove the dependancy on the master page from the Unauthorised view.