ASP.NET CORE – Smart Way to Prevent Cross-Site Request Forgery (CSRF) Attempts – Protect AJAX XHR Requests
Thursday, August 18th, 2022ASP.NET CORE MVC – Protect AJAX Requests from CSRF Attempts
This is a follow-up post related to https://blog.eamster.tk/asp-net-mvc-smart-way-to-prevent-cross-site-request-forgery-csrf-attempts-webapi-ajax-xhr-and-normal-post-operations/
I've modified the code from the linked post above so that it works with ASP.NET CORE. Below is the code that can protect all AJAX requests from CSRF (Cross-Site Request Forgery) attempts. For normal <form> POST requests, you should still use and validate against a CSRF token, but if your application is separated into multiple pieces (for example a node.js React front-end application and a .NET CORE based API), this is an easy way to help prevent CSRF attacks without the use of tokens.
using System; using System.Collections.Generic; using System.IO; using System.Linq; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Filters; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; namespace AnalyticsAPI.Filters { public class CSRFAjaxRequestMitigation : IAuthorizationFilter { public void OnAuthorization(AuthorizationFilterContext filterContext) { IServiceProvider services = filterContext.HttpContext.RequestServices; IConfiguration Configuration = services.GetService<IConfiguration>(); string validOrigins = Configuration.GetValue<string>("AllowedEnvironments"); // Example in appsettings.json "AllowedEnvironments": "https://testurl.com:4443,https://testurl.com,https://testurl2.com", bool skipCheck = false; if(Configuration.GetValue<string>("ENVIRONMENT") == "LOCAL") { skipCheck = true; } // In AJAX requests, the origin header is always sent (UNLESS IT'S COMING FROM THE SAME ORIGIN), so we can validate that it comes from a trusted location to prevent CSRF attacks - but if one isn't sent, we won't do anything (assume trusted) // In which case, we don't need to do any token checking either if (!skipCheck && !string.IsNullOrEmpty(validOrigins)) { List<string> validOriginURLs = validOrigins.Split(',').ToList(); if (!string.IsNullOrEmpty(filterContext.HttpContext.Request.Headers["Origin"].ToString())) { string origin = filterContext.HttpContext.Request.Headers["Origin"]; if (!validOriginURLs.Contains(origin, StringComparer.OrdinalIgnoreCase)) { filterContext.Result = new UnauthorizedResult(); } } } } } public class CSRFMitigationAttribute : TypeFilterAttribute { public CSRFMitigationAttribute() : base(typeof(CSRFAjaxRequestMitigation)) { Arguments = new object[] {}; } } }