CSRF Tokens In ASP.NET Core

CSRF or Cross Site Request Forgery is a type of web attack that uses a users own browser to post a form from one site to another. It works like so :

  • User logs into www.mybankaccount.com and receives a cookie.
  • Sometime later the user goes to www.malicioussite.com and is shown a completely innocuous form on the surface. Something like :
    <form method="POST" action="http://www.mybankaccount.com/sendmoney">
    	<h1>You are a winner! Just click the button below!</h1>
    	<input type="hidden" name="receiveaccount" value="01-0123-1230123-01" />
    	<input type="hidden" name="amount" value="1000" />
    	<input type="submit" value="Click Here" />
    </form>
  • If a user clicks the submit button. Because they are still logged in and have a cookie, the POST request is accepted

Unsurprisingly Wikipedia actually has a pretty good article on the subject and explains it a little better than I do : https://en.wikipedia.org/wiki/Cross-site_request_forgery

The most common way to protect against CSRF attacks is by using a token that is returned on a GET request for a form, and must be present for a POST request to complete. The token must be unique to the user (Cannot be shared), and can either be per “session” or per “request” based. As always, .net core has done most of the leg work for us.

Generating Tokens

If you build a form using ASP.net core helpers then a CSRF token is automatically generated for you without any extra code required.

So both of these :

@using (Html.BeginForm())
{

}

and

<form asp-controller="Home" asp-action="Index" method="post">

</form>

End up generating a form with a request verification token built in :

<form action="/" method="post">
	<input name="__RequestVerificationToken" value="CfDJ8Dn2jF7IZgRPnOI1Rh5gfA0bvW__pdPwyiJ4TQUU-uzoVnIi1bC1xrZI0pY82fwun6pQDY_e_CbsVmIG8heaNjT-Z_HGPJks2IkMocZc2q5jJFUk8grDGtvbU_PNQ4c5EsqBV5QYJ1FgJakRNXWuKyw" type="hidden">
</form>

If you are building forms without using the ASP.net helpers, then you can generate a token manually :

<form method="POST" action="/">
    @Html.AntiForgeryToken()
</form>

Validating Tokens

What good is generating tokens if you don’t validate them! There are two filters in ASP.net core to validate tokens as part of the request pipeline :

  • ValidateAntiForgeryToken – This filter validates the request token on each and every method it’s placed on regardless of the HTTP verb (So it validates even on GET requests).
  • AutoValidateAntiforgeryToken – This filter is almost the same, but it doesn’t validate tokens on GET, HEAD, OPTIONS and TRACE requests.

Typically you are going to use the second option. Very rarely are you going to want to validate GET requests, but it’s there if you need it.

You can apply the filters on an entire controller or action by using it as an attribute :

[AutoValidateAntiforgeryToken]
public class HomeController : Controller

Or you can apply the filter globally if you prefer. In your startup.cs file, find your ConfigureServices method. You should already have a call to AddMvc but you can add a global filter like so :

public void ConfigureServices(IServiceCollection services)
{
	services.AddMvc(options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute()));
}

Adding A Passthrough

You may end up with an endpoint that you actually don’t want to validate CSRF tokens. It may legitimately be receiving POST requests from an outside source. If you have already applied the validate attributes to your controller or globally but need to allow an exception through, you can use the IgnoreAntiforgeryToken attribute on both an Action or a Controller.

[IgnoreAntiforgeryToken]
[HttpPost]
public IActionResult Index()
{
	return View();
}

1 thought on “CSRF Tokens In ASP.NET Core”

Leave a Comment