【问题标题】:Why AntiForgeryToken validation keeps failing?为什么 AntiForgeryToken 验证总是失败?
【发布时间】:2018-06-10 20:40:06
【问题描述】:

我正在开发一个使用asp.net core2 和Angular 运行的网络API 应用程序。详细的开发环境配置为here。 我正在尝试配置AntiForgeryToken 验证,但它一直失败。我按照配置。 here,但我不得不修改它,因为我的 Angular 应用程序和 asp.net 服务器在两个不同的端口上运行,因为前端启动不会生成令牌。我通过在应用程序组件ngOnInit 上调用API 路径(/api/Account/ContactInitialization)来启动后端,这使我能够生成令牌。 配置如下图,

IServiceCollection服务:

        services.AddAntiforgery(options =>
                {
                    options.HeaderName = "X-CSRF-TOKEN";
                    options.SuppressXFrameOptionsHeader = false;
                });

IApplicationBuilder Configure:

app.Use(next => context =>
                {
                    string path = context.Request.Path.Value;
                    if (

                        string.Equals(path, "/", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(path, "/api/Account/ContactInitialization", StringComparison.OrdinalIgnoreCase) ||
                        string.Equals(path, "/index.html", StringComparison.OrdinalIgnoreCase))
                    {
                        // We can send the request token as a JavaScript-readable cookie, 
                        // and Angular will use it by default.
                         var tokens = antiforgery.GetAndStoreTokens(context);
                        context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                            new CookieOptions() { HttpOnly = false });
                    }

                    return next(context);
                });

asp.net。生成两组密钥,

我用[ValidateAntiForgeryToken] 修饰了我的方法,并在我的标头请求中包含了XSRF-TOKEN cookie 内容。但是我在拨打API 后一直收到400 (Bad Request) 回复!我在这里错过了什么?

控制器方法,

    [Authorize]
    [ValidateAntiForgeryToken]
    [HttpPost]
    public IEnumerable<string> AutherizeCookie()
    {
        return new string[] { "Hello", "Auth Cookie" };
    }

我的详细标头请求如下所示,

【问题讨论】:

  • LGTM。尝试从中间件中删除 if 条件?
  • 如果你的意思是生成令牌我没有问题,否则请解释为什么要删除条件

标签: c# asp.net-core-2.0 csrf-protection antiforgerytoken


【解决方案1】:

我假设您可能关注了documentation,但忽略了相关位。到目前为止,您所做的仅适用于 Angular,因为 Angular 的 $http 实际上会基于 XSRF-TOKEN cookie 添加 X-XSRF-TOKEN 标头。 (但请注意,即便如此,您也已将标题设置为 X-CSRF-TOKEN,这实际上在这里不起作用。它必须是 X-XSRF-TOKEN。

但是,如果您不使用 Angular,则您有责任自己在 AJAX 请求中设置标头,而您可能忽略了这样做。在这种情况下,您实际上不需要更改任何防伪令牌配置(标头名称、设置 cookie 等)。您只需将标题提供为RequestVerificationToken。例如,使用 jQuery:

$.ajax({
    ...
    headers:
    {
        "RequestVerificationToken": '@GetAntiXsrfRequestToken()'
    },
    ...
});

这将适用于 JavaScript。如果您需要在外部 JS 中执行此操作,则需要设置 cookie,以便您可以从 cookie 中获取值。除此之外,同样的方法也适用。

如果您只是想更改标题名称,您可以这样做;您只需将此处的RequestVerificationHeader 部分更改为相同的值。

【讨论】:

  • 我正在使用 Angular,它默认附加 cookie,如您所说。我将提供的 Token 标头更改为 X-XSRF-TOKEN 但我仍然得到相同的响应,
  • 代码如下services.AddAntiforgery(options =&gt; { options.HeaderName = "X-XSRF-TOKEN"; }); 和。 var tokens = antiforgery.GetAndStoreTokens(context); context.Response.Cookies.Append("X-XSRF-TOKEN", tokens.RequestToken,..
  • 这篇文章不会太长,但我已经发布了我的启动配置here,在我的代码中,我将标题更改为X-XSRF-TOKEN
  • cookie 名称应该只是 XSRF-TOKEN
  • 更改为var tokens = antiforgery.GetAndStoreTokens(context); context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,我将标题保留为X-XSRF-TOKEN,没有用,我希望我收到错误,除了400错误请求。
【解决方案2】:

您需要发出 XHR 请求 withCredentials=true 这将使浏览器设置 cookie,否则您将收到 400 错误请求,因为 cookie 不存在并且 X-XSRF-TOKEN 未设置或设置为空字符串

【讨论】:

    【解决方案3】:

    感谢@Chris_Pratt 指出我遇到的标题问题。但是,为了清楚起见,我还有其他问题将在下面解决。

    我的CORS 配置错误,我的工作代码如下,

    services.AddCors(options =>
                {
                    options.AddPolicy("CorsPolicy",
                        builder => builder
                            .WithOrigins("https://www.artngcore.com:4200") //Note:  The URL must be specified without a trailing slash (/).
                            .AllowAnyMethod()
                            .AllowAnyHeader()
                            .AllowCredentials());
                });
    
                services.AddAntiforgery(options =>
                    {
                        options.HeaderName = "X-XSRF-TOKEN";
                        options.SuppressXFrameOptionsHeader = false;
                    });  
    

    middleware 配置是,

    app.Use(next => context =>
                   {
                       string path = context.Request.Path.Value;
                       var tokens = antiforgery.GetAndStoreTokens(context);
                       context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken,
                            new CookieOptions() { HttpOnly = false, 
    Secure = true // set false if not using SSL });
                       return next(context);
                   });
    

    在控制器中,

    [Route("/api/[controller]/[action]")]
    [EnableCors("CorsPolicy")]
    public class AccountController : ArtCoreSecuredController ....
    

    这里的诀窍是令牌必须在身份验证后刷新。在身份验证(登录)之后调用 API 即可。 不要忘记将以下标头添加到您的请求中,

     const headers = new HttpHeaders({
                'Content-Type': 'application/json',
                'Authorization': `Bearer ${this.cookieService.get('ArtCoreToken')}`,
                'X-XSRF-TOKEN': `${this.cookieService.get('XSRF-TOKEN')}`
            });
    

    即,

        [HttpGet]
        [AllowAnonymous]
        public async Task<IActionResult> RefreshToken()
        {
            await Task.Delay(1);
    
            return StatusCode(200);
    
        } 
    

    这对我有用。希望对您有所帮助。

    【讨论】:

    • 我不明白为什么要进行 RefreshToken 调用?是因为CORS吗?对我来说,情况几乎相同,只是我没有启用 COR,我需要在我的 web 应用程序中注销并再次登录才能使呼叫正常工作。
    • 请参考这个问题here,根据设计,密钥必须在授权后刷新。
    • 嗯,我对此毫无疑问。不使用ValidateAntiForegeryToken 是否意味着您的控制器实际上并未验证 csrf 令牌,而只是检查 CORS 策略?编辑:实际上只是测试了这个;我从前端删除了实际的 csrf 令牌(请求发送了一个后端未提供的虚拟 csrf 令牌)并且它允许请求
    猜你喜欢
    • 2018-12-28
    • 2016-01-18
    • 1970-01-01
    • 2016-08-24
    • 1970-01-01
    • 2013-01-14
    • 2016-03-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多