Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Validation of the provided antiforgery token failed. The cookie token and the request token were swapped

I have create a ASP.Net Core 2 application using IAntiforgery apis.

This provides a method to return a cookie which it does.

The client takes that cookie and on subsequent POST requests it puts the value in a X-XSRF-TOKEN header.

Middleware validates this and allows the request to continue or not if it fails.

With the correct cookies and headers sent in the request always fails validation and I don't understand why.

The whole reproduction is here https://github.com/jchannon/AntiForgery

However, the main problem area is below.

public class Startup
{
    public void Configure(IApplicationBuilder app, IAntiforgery antiforgery, ILoggerFactory loggerFactory)
    {
        app.UseAuthentication();

        app.Use(async (context, next) =>
        {
            var logger = loggerFactory.CreateLogger("ValidRequestMW");

            //Don't validate POST for login
            if (context.Request.Path.Value.Contains("login"))
            {
                await next();
                return;
            }

            logger.LogInformation(context.Request.Cookies["XSRF-TOKEN"]);
            logger.LogInformation(context.Request.Headers["X-XSRF-TOKEN"]);

            //On POST requests it will validate the XSRF header
            if (!await antiforgery.IsRequestValidAsync(context))
            {

                /****************************************************
                 *
                 *
                 * For some reason when the cookie and the header are sent in on the /create POST this validation always fails
                 * 
                 * 
                 ***************************************************/
                context.Response.StatusCode = 401;

                logger.LogError("INVALID XSRF TOKEN");
                return;
            }
            await next();
        });

        app.UseRouter(r =>
        {
            r.MapGet("", async context => { await context.Response.WriteAsync("hello world"); });

            //This returns a XSRF-TOKEN cookie
            //Client will take this value and add it as a X-XSRF-TOKEN header and POST to /create
            r.MapPost("login", async (context) =>
            {
                antiforgery.SetCookieTokenAndHeader(context);
                context.Response.Redirect("/");
            });

            //If XSRF validaiton is correct we should hit this route
            r.MapPost("create", async context =>
            {
                context.Response.StatusCode = 201;
                await context.Response.WriteAsync("Created");
            });
        });
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddLogging(x => x.AddConsole());

        services.AddAntiforgery(options =>
        {
            options.HeaderName = "X-XSRF-TOKEN";
            options.Cookie.Name = "XSRF-TOKEN";
            options.Cookie.HttpOnly = false;
        });

//        services.AddAuthentication("MyCookieMW")
//                .AddCookie("MyCookieMW", cookieOptions =>
//                {
//                    cookieOptions.Cookie.Name = "MyCookie";
//                    cookieOptions.Cookie.HttpOnly = true;
//                    cookieOptions.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
//                    cookieOptions.SlidingExpiration = true;
//                });

        services.AddRouting();
    }
}
like image 686
Jon Avatar asked Nov 01 '17 10:11

Jon


People also ask

How is Antiforgery token validated?

In ASP.Net Core anti forgery token is automatically added to forms, so you don't need to add @Html. AntiForgeryToken() if you use razor form element or if you use IHtmlHelper. BeginForm and if the form's method isn't GET. And when user submits form this token is verified on server side if validation is enabled.

How does Antiforgery Validate () work?

Validates that input data from an HTML form field comes from the user who submitted the data. Obsolete. Validates that input data from an HTML form field comes from the user who submitted the data and lets callers specify additional validation details.

What is Antiforgery token?

Anti-Forgery Tokens The client requests an HTML page that contains a form. The server includes two tokens in the response. One token is sent as a cookie. The other is placed in a hidden form field. The tokens are generated randomly so that an adversary cannot guess the values.

Why we use validate Antiforgery token?

ValidateAntiForgeryToken: The ValidateAntiForgeryToken attribute is used to prevent cross-site request forgery attacks.


1 Answers

So after diving into the source code of antiforgery and some badly named methods (SetCookieTokenAndHeader I'm looking at you). The correct code should be:

    public void Configure(IApplicationBuilder app, IAntiforgery antiforgery, ILoggerFactory loggerFactory)
    {
        app.Use(async (context, next) =>
        {
            var logger = loggerFactory.CreateLogger("ValidRequestMW");

            //Don't validate POST for login
            if (context.Request.Path.Value.Contains("login"))
            {
                await next();
                return;
            }

            logger.LogInformation("Request Cookie is " + context.Request.Cookies["XSRF-TOKEN"]);
            logger.LogInformation("Request Header is " + context.Request.Headers["X-XSRF-TOKEN"]);

            //On POST requests it will validate the XSRF header
            if (!await antiforgery.IsRequestValidAsync(context))
            {
                context.Response.StatusCode = 401;

                logger.LogError("INVALID XSRF TOKEN");
                return;
            }
            await next();
        });

        app.UseRouter(r =>
        {
            r.MapGet("", async context => { await context.Response.WriteAsync("hello world"); });

            //This returns a XSRF-TOKEN cookie
            //Client will take this value and add it as a X-XSRF-TOKEN header and POST to /create
            r.MapPost("login", async (context) =>
            {
                var tokens = antiforgery.GetAndStoreTokens(context);
                context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, 
                    new CookieOptions() { HttpOnly = false });
                context.Response.Redirect("/");
            });

            //If XSRF validaiton is correct we should hit this route
            r.MapPost("create", async context =>
            {
                context.Response.StatusCode = 201;
                await context.Response.WriteAsync("Created");
            });
        });
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<IAntiforgeryTokenGenerator, MyTokenGenerator>();
        services.AddSingleton<IAntiforgery, MyAntiforgery>();

        services.AddLogging(x => x.AddConsole());

        services.AddAntiforgery(options =>
        {
            options.HeaderName = "X-XSRF-TOKEN";
            options.Cookie.Name = "MyAntiforgery";
            options.Cookie.HttpOnly = false;
        });

        services.AddRouting();
    }
like image 88
Jon Avatar answered Nov 15 '22 05:11

Jon