ASP.NET Core — Angular — XSRF

Pieterjan De Clippel
4 min readJun 14, 2022

--

I’ve created a template specifically for this demo with some pages already in the angular app:

git clone https://github.com/PieterjanDeClippel/XsrfDemo

Open the solution inside the folder.

Refactoring

We’ll start by refactoring the application a bit so that we can also create/update weatherforecasts.

Add the WeatherForecastStore. This is just a wrapper around a List. In real life this would inject a DbContext.

This requires an Id property on the WeatherForecast

Add Id to WeatherForecast

Register the store as a Singleton Service:

Register the store in the application services

And call the Seed method:

Seed the WeatherForecasts on startup

Now modify the existing api controller, and move it to Controllers/Web:

Modify the WeatherForecastController

Add a Create button on top of the weatherforecast overview page:

Now generate a page to add a weatherforecast

cd app/pages/fetch-data
ng g module create --module fetch-data --route add

Import the FormsModule in the create.module.ts

Update the code of the create.component.ts:

Change the WeatherForecast.ts date field to a Date | null .

You can now add + get weather forecasts. Note that we don’t have [Authorize] attributes on the controller methods.

Adding the Antiforgery services

Go to the Program.cs file and add the following line:

Add the Antiforgery services

This will verify if an XSRF token is present on each POST/PUT/DELETE request decorated with the [ValidateAntiForgeryToken] attribute. Add the attribute to the Create, Update and Delete methods of the weatherforecast controller.

If you run the application and try to add a forecast, you’ll get the following:

The request is being blocked

This is because the requests don’t contain a X-XSRF-TOKEN header. Since we’re dealing with a single-page application, we must find a way to return such a token without requiring a page reload. This is done through a javascript cookie. I’ve created a package containing a middleware which returns a cookie with an XSRF-TOKEN.

Open the NuGet package manager and install MintPlayer.AspNetCore.SpaServices.Xsrf in the project.

Add the following line right after the UseHttpsRedirection() middleware:

app.UseAntiforgery();

ctrl+; gives you the suggestion to add the necessary using.

This middleware generates an AntiForgery token and returns it to the angular app through a XSRF-TOKEN cookie (non HttpOnly) on each webrequest.

Now we must instruct the angular app to read this token from the cookie, and send it along in every request as a XSRF-TOKEN header:

Now we can test the application, but you’ll still see the 400 error:

Notice that no XSRF-TOKEN header is being sent by angular:

This is because angular doesn’t send the header when the url starts with http: or https:. So we must remove it from the base-url. Open main.ts and modify the getBaseUrl function:

Now the XSRF-token is being sent along as X-XSRF-TOKEN header, and .NET won’t block your webrequest anymore.

A huge exclamation mark

In MVC webapplications XSRF tokens are generated and included whenever a <form> is returned to the user. A hacker can host his own website http://bad-website.com with a form pointing to your website

<form action="http://my-website.com/posts/create" method="POST">
<input type="hidden" name="content" value="I pooped my pants">
<input type="submit" value="You won € 100.000. Click here to collect it">
<input type="hidden" name="XSRF_TOKEN" id="token" value="I_would_send_it_if_i_could_retrieve_it_somehow">
</form>
<script>
$.get("http://my-website.com/posts/create", function (response) {
const token = processResponseGetXsrfToken(response);
$("#token").val(token);
});
</script>

Your website verifies that the XSRF token corresponds to the authenticated user.

It’s pointless to setup all of the above when pages serving forms to users can be requested from other websites. This essentially means that each page serving a form with an XSRF-token must never serve an Access-Control-Allow-Origin response header.

In single-page-applications, we send an XSRF-token through a javascript-cookie, so other websites must not be able to read this cookie.

Appendix

Please, FFS, use Cookie authentication in your angular app!!!! Your angular app runs in the webbrowser, and ever since the 90’s, cookie authentication is specifically designed to be used by browsers. This walkthrough is an explicit POC of how to use Cross-site request forgery in SPA’s, so use it. The key is

Have I been clear? Let me know in the comments… 😊

The demo can be found in this repository. The library with the Antiforgery middleware, which generates an XSRF-token and attaches the cookie to the HTTP-responses, is hosted here.

Add api controllers

Alas, if you need to develop a mobile app with authentication, you can now add API-controllers which use bearer authentication. A fully-fledged code-repository of an application

  • implementing XSRF protection in the web controllers
  • using Cookie authentication on the web controllers (for your angular app)
  • using Bearer authentication on the api controllers (for your mobile app)

is available here.

--

--