Angular 中的 XSRF/CSRF 保护 - xsrfTokenExtractor.getToken();返回 null

XSRF/CSRF protection in Angular - xsrfTokenExtractor.getToken(); returns null

提问人:jonantony 提问时间:11/9/2023 更新时间:11/9/2023 访问量:34

问:

.NET 7 WebAPI + Angular 前端。

来自 API 调用的示例响应标头:

Access-Control-Allow-Origin:
*
Cache-Control:
no-cache, no-store
Content-Type:
application/problem+json; charset=utf-8
Date:
Wed, 08 Nov 2023 16:45:15 GMT
Pragma:
no-cache
Server:
Kestrel
Set-Cookie:
XSRF-TOKEN=XXXXXXXXXXXXX; path=/
Set-Cookie:
XSRF-TOKEN=XXXXXXXXXXXXX; path=/; samesite=strict; httponly
X-Frame-Options:
SAMEORIGIN

响应状态代码: 。当然是实际的代币。400 Bad RequestXXXXXXXXXXXXX

请求标头:

:authority:
localhost:7129
:method:
POST
:path:
/mycontroller/myendpoint
:scheme:
https
Accept:
application/json, text/plain, */*
Accept-Encoding:
gzip, deflate, br
Accept-Language:
pl-US,pl;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6
Cache-Control:
no-cache
Content-Length:
11
Content-Type:
application/json
Origin:
http://localhost:4210
Pragma:
no-cache
Referer:
http://localhost:4210/
Sec-Ch-Ua:
"Google Chrome";v="119", "Chromium";v="119", "Not?A_Brand";v="24"
Sec-Ch-Ua-Mobile:
?0
Sec-Ch-Ua-Platform:
"Windows"
Sec-Fetch-Dest:
empty
Sec-Fetch-Mode:
cors
Sec-Fetch-Site:
cross-site
User-Agent:
Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36

如您所见,请求中没有任何与 XSRF/CSRF 保护相关的内容,这就是我的端点安全返回的原因[ValidateAntiForgeryToken]400

XSRF 拦截器(角度):

@Injectable()
export class XsrfInterceptor implements HttpInterceptor {
  constructor(private xsrfTokenExtractor: HttpXsrfTokenExtractor) {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    let xsrfToken = this.xsrfTokenExtractor.getToken();

    if (xsrfToken != null) {
      const authorizedRequest = req.clone({
        withCredentials: true,
        headers: req.headers.set('X-XSRF-TOKEN', xsrfToken)
      });

      return next.handle(authorizedRequest);
    } else {  
      return next.handle(req);
    }
  }
} 

在 app.module.ts 中:

providers: [
  {    
    provide: HTTP_INTERCEPTORS,
    useClass: AuthInterceptor,
    multi: true,
  },
  { provide: HTTP_INTERCEPTORS, useClass: XsrfInterceptor, multi: true }    
],

的值是let xsrfToken = this.xsrfTokenExtractor.getToken();null

程序.cs(后端):

var builder = WebApplication.CreateBuilder(args);


builder.Services.AddApplication()
                .AddInfrastructure(builder.Configuration);

builder.Services.AddEndpointsApiExplorer();
var audience = builder.Configuration.GetValue<string>("FpId");

builder.Services.AddAuthentication(o =>
{
    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(o =>
{
    o.RefreshOnIssuerKeyNotFound = true;
    o.MetadataAddress = $"https://securetoken.google.com/{audience}/.well-known/openid-configuration";
    o.Audience = audience;
});

builder.Services.AddCors(options =>
{
    options.AddPolicy(name: "MyCors",
                      builder =>
                      {
                          builder.AllowAnyOrigin()
                          .AllowAnyMethod()
                          .AllowAnyHeader();
                      });
});

builder.Services.AddAuthorization();
builder.Services.AddAntiforgery(options =>
{
    options.HeaderName = "X-XSRF-TOKEN";
    options.Cookie.Name = "XSRF-TOKEN";
});
builder.Services.AddControllersWithViews(options =>
{
    options.Filters.Add(new Microsoft.AspNetCore.Mvc.ValidateAntiForgeryTokenAttribute());
});
var app = builder.Build();
app.UseCors("MyCors");
app.UseHttpsRedirection();

app.UseAuthentication();
app.UseAuthorization();
var antiforgery = app.Services.GetRequiredService<IAntiforgery>();

app.Use((context, next) =>
{
    var requestPath = context.Request.Path.Value;

        var tokenSet = antiforgery.GetAndStoreTokens(context);
        context.Response.Cookies.Append("XSRF-TOKEN", tokenSet.RequestToken!,
            new CookieOptions { HttpOnly = false });
   

    return next(context);
});
app.MapControllers();

app.Run();

为什么? 我的 API 被“托管”(在我的 PC 上本地),而 Angular 打开 - 这会有问题吗?https://localhost:7129http://127.0.0.1:4210/

C# 角度 ASP.NET-WEB-API XSS

评论

0赞 pcalkins 11/9/2023
发送凭据时,不能对 CORS 规则使用通配符。您需要显式指定源、方法和标头。您可能还想在这里查看我的答案,以设置防伪 Angular:stackoverflow.com/questions/77345191/...不要在后端设置 cookie 名称选项...你可以在响应中看到,它覆盖了 cookie,这意味着 Angular 会读取反 csrf 值。
0赞 pcalkins 11/9/2023
我在角度方面所要做的就是在app.module导入部分中“HttpClientXsrfModule.withOptions({ cookieName: 'XSRF-TOKEN', headerName: 'XSRF-TOKEN' })”...并从 '@angular/common/http' 导入 { HttpClientModule, HttpClientXsrfModule };cookieName 是你读取的 cookie 的名称,该 cookie 由后端设置(未设置仅 http)。headerName 是用于发送该值的标头的名称。
0赞 pcalkins 11/9/2023
另请注意,您可能无法读取后端从不同来源设置的 cookie...具有不同端口的 localhost 是哪个。(使整个交易难以从 ng serve 调试......您需要从同一来源构建和服务......
0赞 pcalkins 11/9/2023
此外,如果使用 baseURL,请确保它是相对的。由于某种原因,HttpClientXsrfModule 不允许绝对存在。
0赞 pcalkins 11/9/2023
不过,这一切都可能有点矫枉过正。我认为,如果您需要对所有请求进行自定义标头(可以设置为任何内容),那么您将免受 csrf 的影响,因为会发送预检。

答: 暂无答案