如何在 ASP.NET Core 3.1 中实现自定义 ValidateAntiforgeryTokenAuthorizationFilter

Grz*_*lko 6 csrf antiforgerytoken asp.net-core asp.net-core-webapi

我想实现一个过滤器,在使用身份验证令牌身份验证 ( Bearer)时跳过防伪令牌的验证。

在 ASP.NET Core 2.2 中,ValidateAntiforgeryTokenAuthorizationFilterAutoValidateAntiforgeryTokenAuthorizationFilter是公共的(即使位于Microsoft.AspNetCore.Mvc.ViewFeatures.Internal命名空间中),所以我能够从后者继承并ShouldValidate轻松覆盖该方法。

在 ASP.NET Core 3.0 中,它们变成了内部的,因此不可能只从它们继承。我可以复制粘贴代码,但这显然不是理想的解决方案。

MSDN 的ASP.NET Core文章中关注了防止跨站点请求伪造 (XSRF/CSRF) 攻击,但它并没有真正提到与我的场景相关的任何内容。

itm*_*nus 8

通常,[IgnoreAntiforgeryToken]如果您可以在编译时确定应忽略 csrf 标记,则可以使用属性。如果您想要在运行时拥有这样的能力,您可以创建一个自定义FilterProvider,如果有标题,将提供一个IAntiforgeryPolicyAuthroization: Bearer json-web-token

例如,我们可以创建一个自定义AutoSkipAntiforgeryFilterProvider如下:

public class AutoSkipAntiforgeryFilterProvider: IFilterProvider
{
    private const string BEARER_STRING = "Bearer";
    public int Order => 999;
    public void OnProvidersExecuted(FilterProviderContext context) { }
    public void OnProvidersExecuting(FilterProviderContext context)
    {
        if (context == null) { throw new ArgumentNullException(nameof(context)); }
        if (context.ActionContext.ActionDescriptor.FilterDescriptors != null)
        {
            var headers = context.ActionContext.HttpContext.Request.Headers;
            if (headers.ContainsKey("Authorization"))
            {
                var header = headers["Authorization"].FirstOrDefault();
                if(header.StartsWith(BEARER_STRING,StringComparison.OrdinalIgnoreCase))
                {
                    var FilterDescriptor = new FilterDescriptor(SkipAntiforgeryPolicy.Instance, FilterScope.Last);
                    var filterItem = new FilterItem( FilterDescriptor,SkipAntiforgeryPolicy.Instance);
                    context.Results.Add(filterItem);
                }
            }
        }
    }

    // a dummy IAntiforgeryPolicy
    class SkipAntiforgeryPolicy : IAntiforgeryPolicy, IAsyncAuthorizationFilter
    {
        // a singleton 
        public static SkipAntiforgeryPolicy Instance = new SkipAntiforgeryPolicy();
        public Task OnAuthorizationAsync(AuthorizationFilterContext context) => Task.CompletedTask;
    }
}
Run Code Online (Sandbox Code Playgroud)

并在 Startup 中注册此过滤器提供程序:

services.TryAddEnumerable( ServiceDescriptor.Singleton<IFilterProvider, AutoSkipAntiforgeryFilterProvider>());
Run Code Online (Sandbox Code Playgroud)

现在它会绕过AntiForgery即使有一个[ValidateAntiForgeryToken]属性。


[演示]

假设我们有一个带有注释的操作方法[ValidateAntiForgeryToken]

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] XModel xModel)
{
    ....
}
Run Code Online (Sandbox Code Playgroud)

通常,它会使用 CSRF 令牌保护此方法。但是,如果您发送如下请求:

POST /XModels/Create HTTP/1.1
授权:Bearer Xyz
内容类型:应用程序/x-www-form-urlencoded

...

它不会验证 csrf 令牌。