Antiforgery tokens are reusable
Asked Answered
R

1

19

We use ASP.NET MVC's default Antiforgery technique. Recently a security company did a scan of a form and made note that they could use the same _RequestVerificationToken combination (cookie + hidden field) multiple times. Or how they put it: "The CSRF token in the body is validated on server side but is not revoked after use even though the server generates a new CSRF token."

After reading the documentation and multiple articles on the implementation of Antiforgery, it is my understanding that this is indeed possible as long as the session user matches the user in the tokens.

Part of their recommendation: "Such tokens should, at a minimum, be unique per user session" In my understanding this is already the case, except for anonymous users, correct?

My questions: Is this a security issue? How much of a risk is it? Is there a library that makes sure tokens are not reusable/invalidated.

If not, including an extra random token in session that will be reset on every request sounds like it would solve the issue.

Reedy answered 29/5, 2017 at 15:58 Comment(5)
I guess keeping it in session isn't such a good idea. You could keep requesting forms and the tokens would keep piling up till the session ends.Reedy
Unless you only use one, but then you can't fill out forms on multiple tabs.Reedy
I also put my question on the ASP.NET forum.Reedy
I believe this is the same error. #17224560Unwept
@IgorPaiva I don't see how Seelnium is related to the questionReedy
R
11

The customer eventually agreed that the Antiforgery implementation of ASP.NET is sufficient. Just for fun I wanted to extend Antiforgery to meet the invalidation requirement.

The Antiforgery library has one extensibility point: IAntiforgeryAdditionalDataProvider (Core) and IAntiForgeryAdditionalDataProvider (pre-Core)

In ASP.NET MVC (pre-Core) you can set this on startup.

using System.Web;
using System.Web.Helpers;
// ...

namespace AntiForgeryStrategiesPreCore
{
    public class MvcApplication : HttpApplication
    {
        protected void Application_Start()
        {
            // ...
            AntiForgeryConfig.AdditionalDataProvider = new MyAdditionalDataProvider();
        }
    }
}

For ASP.NET Core you need to register your IAntiforgeryAdditionalDataProvider as a service. If you don't it will use the DefaultAntiforgeryAdditionalDataProvider (source) which does nothing.

using System;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace AntiForgeryStrategiesCore
{
    // ...

    public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IAntiforgeryAdditionalDataProvider, SingleTokenAntiforgeryAdditionalDataProvider>();
            // ...
        }
    }

    // ...
}

Now you can add additional data to your Antiforgery token which will be encypted into your cookie and and form field. Here's a MVC Core example that holds on to a single token in Session, and removes it after usage.

using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;

namespace AntiForgeryStrategiesCore
{
    public class SingleTokenAntiforgeryAdditionalDataProvider : IAntiforgeryAdditionalDataProvider
    {
        private const string TokenKey = "SingleTokenKey";

        public string GetAdditionalData(HttpContext context)
        {
            var token = TokenGenerator.GetRandomToken();
            context.Session.SetString(TokenKey, token);
            return token;
        }

        public bool ValidateAdditionalData(HttpContext context, string additionalData)
        {
            var token = context.Session.GetString(TokenKey);
            context.Session.Remove(TokenKey);
            return token == additionalData;
        }
    }
}

This isn't recommended because when you open multiple tabs with multiple forms, only one of the forms will have the valid token in session, and the other will fail. That's why I made one that holds on to multiple tokens. You can find that AdditionalDataProvider and others on GitHub (Time based, Queue based).

Reedy answered 28/7, 2017 at 19:48 Comment(2)
Since this is "additional" validation, do we need to validate the base csrf token, or it's already validated by reaching this step?Orphism
@Orphism It will do the default AntiForgery validation and call your AdditionalData validation on top.Reedy

© 2022 - 2024 — McMap. All rights reserved.