Reputation: 2803
I'd like to implement a filter that skips validation of an antiforgery token when an auth token authentication (Bearer
) is used.
In the ASP.NET Core 2.2 the ValidateAntiforgeryTokenAuthorizationFilter
and AutoValidateAntiforgeryTokenAuthorizationFilter
were public (even though living in the Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
namespace), so I was able to just inherit from the latter and override the ShouldValidate
method easily.
In the ASP.NET Core 3.0 they became internal, so it's not possible to just inherit from them. I can just copy-paste the code, but it's not the ideal solution obviously.
I was following the Prevent Cross-Site Request Forgery (XSRF/CSRF) attacks in ASP.NET Core article from MSDN, but it doesn't really mention anything relevant to my scenario.
Upvotes: 10
Views: 7546
Reputation: 25350
Normally you can use [IgnoreAntiforgeryToken]
attribute if you can determine at compile-time that the csrf token should be ignored. If you want such an ability at run-time, you could create a custom FilterProvider
that will provide an IAntiforgeryPolicy
if there's a Authroization: Bearer json-web-token
header.
For example, we can create a custom AutoSkipAntiforgeryFilterProvider
as below:
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;
}
}
And register this filter provider in Startup :
services.TryAddEnumerable( ServiceDescriptor.Singleton<IFilterProvider, AutoSkipAntiforgeryFilterProvider>());
Now it will bypass the AntiForgery
even there's a [ValidateAntiForgeryToken]
attribute.
[Demo]
Assume we have an action method annotated with [ValidateAntiForgeryToken]
:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Name")] XModel xModel)
{
....
}
Normally, it will protect this method with CSRF token. But if you send a request like:
POST /XModels/Create HTTP/1.1 Authorization: Bearer Xyz Content-Type: application/x-www-form-urlencoded ...
it won't validate the csrf token.
Upvotes: 16