create separate API methods for tokens (short-lived) and personal access tokens (long-lived), include global antiforgery filter to mitigate XSRF when using cookie auth (ignored when using Jwt)

This commit is contained in:
Shaun Walker
2022-04-14 19:41:43 -04:00
parent c616878a64
commit f6b3874668
9 changed files with 120 additions and 6 deletions

View File

@ -0,0 +1,19 @@
using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
namespace Oqtane.Security
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class AutoValidateAntiforgeryTokenAttribute : Attribute, IFilterFactory, IOrderedFilter
{
public int Order { get; set; } = 1000;
public bool IsReusable => true;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<AutoValidateAntiforgeryTokenFilter>();
}
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Antiforgery;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
namespace Oqtane.Security
{
public class AutoValidateAntiforgeryTokenFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy
{
private readonly IAntiforgery _antiforgery;
public AutoValidateAntiforgeryTokenFilter(IAntiforgery antiforgery)
{
_antiforgery = antiforgery;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (!context.IsEffectivePolicy<IAntiforgeryPolicy>(this))
{
return;
}
if (ShouldValidate(context))
{
try
{
await _antiforgery.ValidateRequestAsync(context.HttpContext);
}
catch
{
context.Result = new AntiforgeryValidationFailedResult();
}
}
}
protected virtual bool ShouldValidate(AuthorizationFilterContext context)
{
// ignore antiforgery validation if a bearer token was provided
if (context.HttpContext.Request.Headers.ContainsKey("Authorization"))
{
return false;
}
// ignore antiforgery validation for GET, HEAD, TRACE, OPTIONS
var method = context.HttpContext.Request.Method;
if (HttpMethods.IsGet(method) || HttpMethods.IsHead(method) || HttpMethods.IsTrace(method) || HttpMethods.IsOptions(method))
{
return false;
}
// everything else requires antiforgery validation (ie. POST, PUT, DELETE)
return true;
}
}
}