Search code examples
c#asp.net-mvcxssaction-filter

Asp.Net MVC ActionFilter to validate query params for xss


I had the situation where I wanted to do query parameter (not form parameter) xss handling* for all of my MVC flows (and hence ActionFilter was ideal); but even on Microsoft docs I couldn't find a good implementation of this (Which I thought is a very typical scenario)

So creating this wiki format of Q&A (will post my code as an answer) to publish the implementation which solved my scenario

*When I say xss handling, I wanted the code to redirect to login page (rather than let ASP.NET MVC redirect it to lets say the error page which we can control via web.config customErrors mode="On")


Solution

  • Here is the implementation that worked for the use-case I mention in the question

    using System;
    using System.Web.Mvc;
    using System.Web.Routing;
    using System.Web.Security.AntiXss;
    
    namespace SomeAttribute
    {
        public class QueryParamsXssValidate : ActionFilterAttribute
        {
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                try
                {
                    var qs = filterContext.HttpContext.Request.QueryString;
    
                    foreach (var keyRecvd in qs.AllKeys)
                    {
                        var keyEncd = AntiXssEncoder.HtmlEncode(keyRecvd);
                        if (keyEncd != keyRecvd)
                        {
                            throw new ArgumentException($"Potentially dangerous keyRecvd: {keyRecvd}");
                        }
    
                        var valRecvd = qs[keyRecvd];
                        var valEncd = AntiXssEncoder.HtmlEncode(valRecvd);
                        if (valEncd != valRecvd)
                        {
                            throw new ArgumentException($"Potentially dangerous valRecvd: {valRecvd}");
                        }
                    }
                }
                catch (ArgumentException e)
                {
                    //logging
                    loginRedirect(filterContext); //alternatively, create ExceptionHandlerAttribute and rethrow here
                }
            }
    
            private void loginRedirect(ActionExecutingContext filterContext)
            {
                filterContext.Result = new RedirectToRouteResult(
                    new RouteValueDictionary
                    {
                        {"controller", "main"},
                        {"action", "login"},
                        {"error", filterContext.HttpContext.Request.QueryString["error"] ?? string.Empty}
                    });
            }
        }
    }