在ASP .NET Core Web API中使用无身份认证的cookie认证时,如何在登录时刷新CSRF令牌?

问题描述 投票:0回答:1

我有一个ASP.NET Core 3.1的后台,前台是angular 9(基于dotnet angular模板,只是更新了angular到v9).我使用cookie认证(我知道JWT更适合SPA,就当是实验吧),我还在服务器端增加了对CSRF保护的支持。

services.AddAntiforgery(options =>
{
   options.HeaderName = "X-XSRF-TOKEN"; // angular csrf header name
});

我在服务器端设置了自动检查CSRF的功能,使用的是

options => options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute())

所以GET请求不会被CSRF检查,但POST会。

在最开始的时候,angular应用会向以下地方发出GET请求 api/init 来获取一些启动前的初始数据。在服务器端,这个动作初始化CSRF如下。

// init action body
var tokens = _antiForgery.GetAndStoreTokens(HttpContext);
Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions
{
   HttpOnly = false
});
// return some inital data DTO

这和预期的一样--GET响应包含2个CSRF cookie--第一个是ASP .NET core dafault CSRF cookie。.AspNetCore.Antiforgery... 二是 XSRF-TOKEN 角度将读取并放入 X-XSRF-TOKEN 头,用于后续请求。

如果之后我真的登录了(POST请求中包含了对 api/auth/login),一切都正常了--请求被POSTed,包括 X-XSRF-TOKEN 头和CSRF验证通过,所以如果凭证正确,用户就可以登录。

现在问题就从这里开始了。ASP .NET服务器应用程序使用了这里描述的无身份认证的cookie认证。https:/docs.microsoft.comen-usaspnetcoresecurityauthenticationcookie?view=aspnetcore-3.1。. 在登录操作中,CSRF令牌也需要重新生成,因为在认证时,CSRF令牌开始包含认证用户的身份。因此,我的登录动作是这样的。

public async Task<IActionResult> Login(CredentialsDto credentials)
{
   // fake user credentials check
   if (credentials.Login != "admin" || credentials.Password != "admin")
   {
      return Unauthorized();
   }

   var claimsIdentity = new ClaimsIdentity(new[]
   {
     new Claim(ClaimTypes.Name, "theAdmin"),
   }, CookieAuthenticationDefaults.AuthenticationScheme);

   var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
   await HttpContext.SignInAsync(claimsPrincipal); 

   // refresh antiforgery token on login (same code as in init action before)
   var tokens = _antiForgery.GetAndStoreTokens(HttpContext);
   Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions 
   {
       HttpOnly = false
   });

   return new JsonResult(new UserDto { Id = 1, Login = "theAdmin" });
}

这个动作不工作. 响应包含以下内容 XSRF-TOKEN cookie,但随后的POST请求(在我的例子中,它的logout = POST到 api/auth/logout)以400失败,尽管angular正确地将这个cookie值放到了 X-XSRF-TOKEN 我相信原因是dafault的 "头像"。.AspNetCore.Antiforgery... 由于某种原因,cookie在响应中没有被设置,因此即使在登录后也保留了原始值,因此CSRF检查失败,因为值不匹配。

这种情况下,如何正确刷新CSRF令牌?

angular asp.net-core authentication asp.net-web-api csrf
1个回答
0
投票

又做了一些试错,也搜索了ASP .NET github,找到了 https:/github.comdotnetaspnetcoreissues2783。https:/github.comaspnetAntiforgeryissues155。但似乎我想实现的目标无法在单个请求中实现,因为在单个请求处理过程中,用户的身份不会改变(设计上的pearentyl)。

唯一的办法是在登录退出后再进行额外的请求,这样CSRF token就会根据新获得的身份正确刷新。

我是通过我的登录动作返回一个302重定向来实现的,当遵循这个重定向时,就会执行CSRF刷新。注销时也需要这样做。

副作用是请求量增加了一倍,而且可能会出现Angular跟随重定向的问题(我在Chrome浏览器中使用Angular 9的时候就能用,但是网上有很多关于Angular的HttpClient不跟随重定向的抱怨)。另外,当登录请求成功,但由于某种原因跟随重定向到token刷新失败时,你可能最终会陷入一个limbo状态--那么你就会被过时的CSRF token所困。所以,不是很好,也不是很糟糕...

© www.soinside.com 2019 - 2024. All rights reserved.