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.
In ASP.NET Core, @Html. AntiForgeryToken() is applied for preventing cross-site request forgery (XSRF/CSRF) attacks.
Validates that input data from an HTML form field comes from the user who submitted the data and lets callers specify additional validation details.
MVC's anti-forgery support writes a unique value to an HTTP-only cookie and then the same value is written to the form. When the page is submitted, an error is raised if the cookie value doesn't match the form value. It's important to note that the feature prevents cross site request forgeries.
Cross-site request forgery, also known as one-click attack or session riding and abbreviated as CSRF (sometimes pronounced sea-surf) or XSRF, is a type of malicious exploit of a website or web application where unauthorized commands are submitted from a user that the web application trusts.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With