自定义 ASP.NET Core 的 AntiForgery 失败响应

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

我想自定义 CSRF 令牌验证失败时客户端收到的响应。我正在查看 ASP.NET 的源代码,发现一个我认为可以处理这个问题的中间件。

通过查看它,我发现它在验证失败时设置了一个带有错误的

IAntiForgeryValidationFeature

,因此我创建了一个中间件来检查这一点。

public class CustomAntiForgeryValidationResponseMiddleware(RequestDelegate next) { public async Task InvokeAsync(HttpContext context) { IAntiforgeryValidationFeature? antiforgeryValidation = context.Features.Get<IAntiforgeryValidationFeature>(); if (antiforgeryValidation is not null && !antiforgeryValidation.IsValid) { context.Response.StatusCode = 403; await context.Response.WriteAsJsonAsync(new ProblemDetails() { Title = "Forbidden", Detail = "User is not allowed to perform this action", Status = 403, Extensions = new Dictionary<string, object?>() { { "errors", new ApiError[] { new("Invalid or missing CSRF token") } } } }); } await next(context); } }
然后,我在请求管道中的身份验证中间件之前添加了中间件。

app.UseMiddleware<CustomAntiForgeryValidationResponseMiddleware>(); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
但是,即使在需要 CSRF 令牌的端点上,该功能也始终为空。我做错了什么?

c# asp.net-core
1个回答
0
投票
一般来说,防伪令牌验证失败会抛出 400 bad request 错误。另外,如果请求数据无效,也会返回400 bad request错误。

因此,在捕获防伪令牌验证异常之前,我们需要了解

防伪令牌工作流程

为了帮助防止 CSRF 攻击,ASP.NET MVC 使用防伪造令牌,也称为请求验证令牌。

  1. 客户端请求包含表单的 HTML 页面。服务器 响应中包含两个令牌。一个令牌作为 cookie 发送。
  2. 另一个放置在隐藏的表单字段中。代币已生成 随机,这样对手就无法猜测这些值。当 客户端提交表单,它必须将两个令牌发送回服务器。
  3. 客户端将 cookie 令牌作为 cookie 发送,并发送表单 表单数据内的令牌。 (浏览器客户端会自动执行此操作 当用户提交表单时。)
  4. 如果请求不包含两个令牌,服务器将不允许该请求。
因此,您可以尝试使用

UseStatusCodePages

方法
捕获400错误并检查请求头或表单是否包含Anti-Forgery token:如果请求头或表单不包含Anti-Forgery token ,这是一个Anti-Forgery token异常,代码如下:

app.UseStatusCodePages(async context => { var response = context.HttpContext.Response; if (response.StatusCode == 400 ) { //check Anti-Forgery Tokens workflow: https://learn.microsoft.com/en-us/aspnet/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks#anti-forgery-tokens if (!context.HttpContext.Request.Headers.ContainsKey("RequestVerificationToken") & !context.HttpContext.Request.Form.ContainsKey("__RequestVerificationToken")) { //Anti-Forgery Tokens exceptions response.StatusCode = StatusCodes.Status403Forbidden; await response.WriteAsync("Antiforgery token validation failed."); } else { //other model validation error await response.WriteAsync("Other 400 error."); } } }); app.UseHttpsRedirection(); app.UseRouting(); app.UseAuthorization();
    
© www.soinside.com 2019 - 2024. All rights reserved.