Creating a mandatory Anti-Forgery token

Published | 5 min read

One of the things I love about ASP.Net, is that a lot of the hard work that is required for a creating a secure website has already been done for you. It usually only takes a couple of lines of code to add these features in which means there are no excuses for missing off important security measures.

Anti-Forgery Token

One of these features is the Anti-Forgery token and it can be added to your MVC website with just 2 lines of code. So what is an anti-forgery token? As the name suggests it is a token to prevent forgery! In the same way that someone might forge a signature to pretend to be someone else, it is possible for a malicious person to forge a request to your website without the request coming from your website.

So how is this done I hear you say? Well lets say you have a form on your website for changing user details such as name and email address, and a hacker wanted to change these to something else.

The hacker could create a form on another website which matches the request your website is expecting and post to the same URL. The entire form could be in hidden fields and posted via an Ajax request on page load making it invisible to the user.

If the user is already logged in to your website when the other website posts the form, your website treats it as a valid request and will change the user details to whatever the hacker wants.

So how do we get around this?

Well in the same way that 2 factor authentication works on something you know and something you have. The anti-forgery token works as the something you have (sorry about the poor analogy). The server places a hidden field with a populated anti-forgery token into your form. When a request is made to your website, the server checks for the presence of the anti-forgery token and if it doesn’t exist or doesn’t match the expected value an exception occurs.

As the hackers malicious form doesn’t know what the Anti-Forgery token is the request fails.

Adding an Anti-Forgery token

This all sounds great so how do you add this in? As i mentioned you only need 2 lines of code to add in an Anti-Forgery token, one in the view and one in the controller.


In the view you need to add in the anti-forgery token with @Html.AntiForgeryToken() inside your post form like this:

@using (Html.BeginForm("Login", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{ @Html.AntiForgeryToken()


The controller then needs to have the [ValidateAntiForgeryToken] added to the post action.

// POST: /Account/Login
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{ if (!ModelState.IsValid) { return View(model); }

If you look at the source code of your page you should now see the following in your form (with a different value of course):

<input name="__RequestVerificationToken" type="hidden" value="JN8mexoJ6sCyfy9TzagXr1DSmjk6au-5VfP9IN_EyLhkWwvd-w2HGJ5EzCW1e_W9nf3wpTQWG_bDgDFFhzLWU8EqAb_8uQtXTwvojSTe3541">

Ok so lets test it by changing the value in this hidden field and seeing what happens.<input name="__RequestVerificationToken" type="hidden" value="bad token">Anti Forgery Exception

As shown above we get the expected exception that the anti-forgery token could not be decrypted. In production you will have custom errors turned on so the user will see a nice error message instead of a stack trace which is dangerous in itself.

Making the Anti-Forgery token mandatory

As you might have guessed from the title of this post, we aren’t finished yet. If you are working in a team it is possible that someone might forget to add the anti-forgery token into their new view and action. So what happens if you forget to add the token to the view?

Anti Forgery Missing Exception

As you would expect you get an exception saying that the token is missing. Great, but what happens if you forget to add the ValidateAntiForgeryToken to the action?

Nothing. No exception. It just allows it through.

Given that you have to add an attribute to every post action it is conceivable to think one could be missed. We can mitigate this issue by doing 2 things:

1.) Use an HTML Helper Extension for BeginForm to always add in the token. 2.) Write a unit test to check for the presence of the ValidateAntiForgeryToken on every Post action.

So how do we do this: 1.) Use an HTML Helper extension for BeginForm To create a HTML Helper extension we are going to create a new class called HtmlExtensions and place it somewhere in our project. You then need to add the following method:

public static MvcForm BeginFormWithToken( this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
    var form = htmlHelper.BeginForm(actionName, controllerName, routeValues, method, htmlAttributes);
    return form;

Now I have only created one for the BeginForm method shown above but you will probably want to create one for each of the other overloads you use. You will then need to go through each of your views and change BeginForm to BeginFormWithToken. So now we have the Anti-Forgery token being added to every form.

2.) Write a unit test to check for the presence of the ValidateAntiForgeryToken To do this we have to use reflection to find all the controller actions with HttpPost and check that they have a ValidateAntiForgeryToken present. In the example below you will need to change MyWebApplication to the name of your Web project.

public void TestValidateAntiForgeryTokenAttributeOnAllPostActions()
    // Act
    var actions = Assembly.Load("MyWebApplication").GetTypes()
                        .Where(t => typeof(Controller).IsAssignableFrom(t))SelectMany(type => type.GetMethods()).Where(method => method.IsPublic &&
                        method.GetCustomAttributes(typeof(HttpPostAttribute), true).Any() &&
                        !method.GetCustomAttributes(typeof(ValidateAntiForgeryTokenAttribute), true).Any()).ToList();
    // Assert
    Assert.IsFalse(actions.Any(), actions.Any() ? $"The action '{actions[0].Name}' in the '{actions[0].DeclaringType.Name} ' controller is missing the ValidateAntiForgeryToken attribute." : string.Empty);

This test will fail if any of the actions are missing the validate attribute and will give the name of the first offender. Feel free to modify this. For example you might want to get it to print out all of the actions that are missing the Anti-Forgery token attribute.

If this post was helpful please leave a comment below.


Stack vs Heap Memory - What are the differences?

Stack vs Heap Memory - What are the differences?

  • 30 November 2022
In modern programming languages such as C# or Java, we tend to take memory management for granted. Gone are the days when we need to call malloc to request enough memory for our variables. Luckily a lot of that is done for us by the runtimes so we do...
Code Katas: Can They Make You A Better Developer?

Code Katas: Can They Make You A Better Developer?

  • 21 November 2022
They say “practice makes perfect”, although I much prefer “practice makes improvement”. Either way, how do you practice being a programmer? If you are already working as a software developer then you will be getting some practice from working on larg...
Git Flow vs GitHub Flow

Git Flow vs GitHub Flow

  • 10 November 2022
Losing code that you have spent hours writing can be painful, which is why we use version control (or source control) to store our code and manage changes. Version control is even more important if you are working in a team, without it code, changes ...
I Posted on YouTube Consistently for 1 Month. This is What Happened!

I Posted on YouTube Consistently for 1 Month. This is What Happened!

  • 02 November 2022
As part of my creative sabbatical, I have been posting a new software development video on my YouTube channel every Monday and Friday. It takes a long time to grow on YouTube, and I knew this going in but I have been pleasantly surprised with my grow...
Bitwise Operators and WHY we use them

Bitwise Operators and WHY we use them

  • 26 October 2022
Bitwise operators are one of those concepts that a lot of programmers don’t understand. These are not used a great deal anymore so you can get away with not knowing them but they can still come in handy for a number of different scenarios. If you end...
8 Data Structures you NEED to Know

8 Data Structures you NEED to Know

  • 26 October 2022
You can get pretty far in programming without understanding Data Structures, but eventually, you are going to need to know them, understand how they work and when to use them. What is a data structure? A da...
Binary Numbers Explained for Programmers

Binary Numbers Explained for Programmers

  • 21 October 2022
Everyone knows that computers run on ones and zeros. This is because CPUs are made up of billions of transistors, which are basically just on-off switches. Any code you write needs to be processed by a computer and therefore has to be converted to b...
Beginners Guide to Programming

Beginners Guide to Programming

  • 12 October 2022
A lot of my articles are aimed at intermediate to advanced developers, but as part of my creative sabbatical, I am working on creating content for those just starting out. So in this post I will be covering some of the many questions that beginner pr...