【问题标题】:Validation of the provided antiforgery token failed. The cookie token and the request token were swapped验证提供的防伪令牌失败。交换了 cookie 令牌和请求令牌
【发布时间】:2018-04-13 15:39:03
【问题描述】:

我使用IAntiforgery api 创建了一个 ASP.Net Core 2 应用程序。

这提供了一种方法来返回它所做的 cookie。

客户端获取该 cookie,并在随后的 POST 请求中将值放入 X-XSRF-TOKEN 标头中。

中间件对此进行验证,并允许请求在失败时继续或不继续。

在请求中发送正确的 cookie 和标头时,验证总是失败,我不明白为什么。

完整再现在这里https://github.com/jchannon/AntiForgery

但是,主要问题区域如下。

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();
    }
}

【问题讨论】:

    标签: asp.net asp.net-core .net-core asp.net-core-2.0


    【解决方案1】:

    所以在深入研究了防伪的源代码和一些名字不好的方法之后(SetCookieTokenAndHeader我在看着你)。正确的代码应该是:

        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();
        }
    

    【讨论】:

    • 是的,正如我刚刚在我的应用程序中发现的那样,您的代码的问题在于 services.AddAntiforgery 使用它用来验证实际令牌的 csrf 秘密创建了自己的 cookie。这被称为双重提交 Cookie 方法,这是有道理的,因为 csrf 机密不会像在其他框架中那样存储在会话中
    猜你喜欢
    • 2018-07-11
    • 2018-06-19
    • 2014-01-23
    • 2019-11-19
    • 2014-10-08
    • 2017-12-29
    • 2011-01-19
    • 2018-08-30
    • 2021-06-09
    相关资源
    最近更新 更多