Asynchronous JavaScript with async/await

In this course we will learn how to use the ES2017 async and await keywords to write asynchronous code that is more readable and easier to follow than equivalent code based on long promise chains or deeply nested callbacks.

Watch the Course

Global Antiforgery Token Validation in ASP.NET Core

In this blog post, I want to share a small piece of ASP.NET Core middleware that implements antiforgery token validation for all POST requests.

Update (June 12th, 2017): In the meantime, Andrew Lock has blogged about using the built-in [AutoValidateAntiforgeryTokenAttribute] for validating all requests. Make sure to check out his post as well!

If you're not yet familiar with cross-site request forgery (CSRF/XSRF) or antiforgery tokens as a defense mechanism, I recommend you read the following articles first:

Before we take a look at the middleware itself, let's recap how we can secure each ASP.NET MVC controller action manually, one by one.

The Manual Approach

To secure a controller action against CSRF, we can decorate it with the [ValidateAntiForgeryToken] attribute. The action will then only execute if the HTTP request contains a valid antiforgery token:

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Logout()
{
    // ...
    return View();
}

Within our Razor views, we can use the @Html.AntiForgeryToken() method to have the framework generate a hidden <input> holding the expected antiforgery token:

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

This approach works, but it has a drawback: We have to manually decorate every controller action that deals with POST requests with the [ValidateAntiForgeryToken] attribute, which is a little cumbersome. More importantly, though, it's quite easy to forget to add the attribute, which makes the corresponding controller action vulnerable to CSRF attacks.

Let's see how we can implement the antiforgery token validation in a single place so that it "just works" for all POST requests.

Using Middleware to Validate Antiforgery Tokens

Here's the middleware in its entirety:

using System.Threading.Tasks;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;

public class ValidateAntiForgeryTokenMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IAntiforgery _antiforgery;

    public ValidateAntiForgeryTokenMiddleware(RequestDelegate next, IAntiforgery antiforgery)
    {
        _next = next;
        _antiforgery = antiforgery;
    }

    public async Task Invoke(HttpContext context)
    {
        if (HttpMethods.IsPost(context.Request.Method))
        {
            await _antiforgery.ValidateRequestAsync(context);
        }

        await _next(context);
    }
}

The idea is that we check whether the current HTTP request is a POST request, and if it is, we validate that it was sent with a correct antiforgery token. This validation functionality is provided by the IAntiforgery service, which we resolve via the constructor of the middleware.

If the request does not contain a valid antiforgery token, the ValidateRequestAsync method will throw an AntiforgeryValidationException. In this case, _next(context) will not be called and the rest of the request pipeline won't be executed. It is then up to some error handling middleware to display an error to the user.

Adding Our Middleware to the Request Pipeline

Of course, simply creating the middleware class is not enough. We have to instantiate it and add it to the request pipeline to take effect:

public void Configure(IApplicationBuilder app)
{
    // ...
    app.UseAntiforgeryTokens();
    // ...
}

Here, I've written a simple extension method that follows the Use... naming scheme which is common in ASP.NET Core:

using Microsoft.AspNetCore.Builder;

public static class ApplicationBuilderExtensions
{
    public static IApplicationBuilder UseAntiforgeryTokens(this IApplicationBuilder app)
    {
        return app.UseMiddleware<ValidateAntiForgeryTokenMiddleware>();
    }
}

And there we go! We now automatically validate antiforgery tokens for each POST request.

Further Reading

Learn Node