Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XSS validation from MVC action from JSON ajax post

Is there a way to manually call the XSS detection from MVC, such as from a filter, in cases when json is posted to an MVC action (like $.ajax post from JQuery with json content)?

We are using MVC 5 and have no issues with standard MVC mechanisms for catching XSS ("potentially unsafe input detected"), but a few pieces of the app use $.ajax to post JSON ("application/json" content type) to an MVC action. In these situations, we noticed the XSS detection does not run and allows dangerous form input.

In our investigation and research of similar questions here, we found JsonValueProviderFactory within the default model binder does not have same call for this XSS security that is present on form submissions or input from query string.

While it is easy to sanitize the input on client side, we obviously need a server validation as well in order to throw a 5xx (possibly something I can wrap in a filter to share across actions that could be impacted) to force this dangerous code detection on json submitted input with default model binding if possible to avoid re-inventing the wheel or inserting html encoded bad input to our db.

like image 300
Jason W Avatar asked Aug 23 '17 18:08

Jason W


1 Answers

I found a solution that works for my situation. In this case, we had JQuery using $.ajax to post JSON to the MVC action. The default model binder does not validate posted JSON allowing unsafe XSS to be posted against our action.

To solve this, I found the RequestValidator has a static method InvokeIsValidRequestString that allowed validating a specific string to detect XSS (since every solution I had found until now reinvented the wheel here and did own XSS check for white/black list). Then it was just a matter of limiting the action to the appropriate scenario, getting the posted JSON, and throwing the validation error if XSS was detected.

public class ValidateJsonXssAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var request = filterContext.HttpContext?.Request;
        if (request != null && "application/json".Equals(request.ContentType, StringComparison.OrdinalIgnoreCase))
        {
            if (request.ContentLength > 0 && request.Form.Count == 0) // 
            {
                if (request.InputStream.Position > 0)
                    request.InputStream.Position = 0; // InputStream has already been read once from "ProcessRequest"
                using (var reader = new StreamReader(request.InputStream))
                {
                    var postedContent = reader.ReadToEnd(); // Get posted JSON content
                    var isValid = RequestValidator.Current.InvokeIsValidRequestString(HttpContext.Current, postedContent,
                        RequestValidationSource.Form, "postedJson", out var failureIndex); // Invoke XSS validation
                    if (!isValid) // Not valid, so throw request validation exception
                        throw new HttpRequestValidationException("Potentially unsafe input detected");
                }
            }
        }
    }
}

Then, I can just decorate relevant MVC actions expecting JSON-posted data that might bypass the standard XSS prevention:

[HttpPost]
[ValidateJsonXss]
public ActionResult PublishRecord(RecordViewModel vm) { ... }

I was fortunate to stumble on thet OWASP .NET recommendations in which it recommended extending the RequestValidator object, which exposes the string validation done by the ValidateInput automatically utilized by MVC for other scenarios of query string, form collection, and cookie values.

For more info: https://www.owasp.org/index.php/ASP.NET_Request_Validation

If anyone has other recommendations, I would love to see other approaches.

like image 65
Jason W Avatar answered Nov 06 '22 15:11

Jason W