提供的防伪令牌的验证失败。cookie 令牌和请求令牌已交换

Jon*_*Jon 8 asp.net .net-core asp.net-core asp.net-core-2.0

我已经使用IAntiforgeryapis创建了一个 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*Jon 5

因此,在深入研究了反伪造的源代码和一些命名不当的方法之后(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();
    }
Run Code Online (Sandbox Code Playgroud)

  • 是的,正如我刚刚在我的应用程序中发现的那样,您的代码存在的问题是 services.AddAntiforgery 使用 csrf 秘密创建了自己的 cookie,用于根据实际令牌进行验证。这称为双重提交 Cookie 方法,这是有道理的,因为 csrf 机密不像在其他框架中那样存储在会话中 (2认同)