Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Prevention

In the last Cross Site Scripting (XSS) post: Secure Sitecore : Cross Site Scripting (XSS) Vulnerability Findings , we looked at how these attacks might look based on the browser the user is using. The interesting factor is that a potential attacker might not use a browser at all. You do not need a browser to initiate requests and process them. Fuzzing is a common technique where an attacker can create potentially invalid requests from scratch to perform testing on applications, to see how they respond.

Environment testing was done on two Windows 10 machines with Sitecore 8.1 update 3. Browsers use were Chrome (), Firefox (47.0.1), Microsoft Edge (25.10586.0.0 and Internet Explorer 11 (11.494.10586.0).

I would also recommend that you go through the post: Sitecore Security #3: Prevent XSS using Content Security Policy by Bas Lijten. Content headers can enforce security on browsers. Remember, each browser acts differently.

Based on the last post, I want to show you how to add in custom validation on requests. Because we are on 4.5, we have the ability to specify a Custom Request Validator. To do this lets do an sample in a true ASP.NET MVC application.

I created a sample MVC application with no custom coding. I added the following class for a custom Request Validator:

Here is are the web.config entries related to compilation and httpRuntime:

The output is what we expected. Any request with a QueryString will and should result in an error.
xss21

The default ASP.NET MVC app, hits the return false which causes the invalid value error and stops.

Now lets take the default Sitecore install and make the same change by adding the CustomRequestValidation.

Lets open the site using some QueryString params and see what happens.
xss23

As you can see, Sitecore somehow seems to move past it and continues to evaluate the other parameters. My initial thought was to some how detect the additional tags via the CustomRequestValidation but now that doesn’t look feasible.

There is processor called SupressFormValidation which triggers even before the CustomRequestValidation and here Sitecore basically suppresses the validations for specific urls. In doing so, my previous article show that we are getting inconsistent results. The default SupressFormValidation code is shown below:

Here is a possible remedy. Get the web.config back to normal without the CustomRequestValidation. We validate our query string parameters against RFC 3986 and if its violated we throw an error. Here is the modified SupressFormValidation:

Here is the patch config:

Now if we run the tests using urls regardless of the encoding:

xss26

xss24

xss25

The system functions the way we expect it to on top of the base validation by ASP.NET. Now if we get in to the Sitecore admin, we have no issues modifying items etc.

xss27

This is not limited to what I did, you can evaluate Form posts, cookies etc. You can check encoding as well as any custom rules you have for your system to be secure. We no longer have security mishaps when Chrome or FF encode their inputs.

Remember, we did not set the validation mode to 2.0, we left the default web.config and sitecore.config which defaults to framework 4.5.

 
If you have any questions or concerns, please get in touch with me. (@akshaysura13 on twitter or on Slack).

4 comments

  • Jey 1 year ago

    How does a noncoder – at least not any more, figure out whether this is an issue? What kind of questions should I ask, Akshay?

    Best,
    Jey

  • akshaysuraadmin 1 year ago

    Hi Jey, thanks for reading my post and that was quick! 😉 This is something which should be in build and the in house team and the security team has to work hand in hand in preventing. In large organizations, it is the security team which takes this responsibility but I would hold the developers accountable as well. There are several tools available online which let you do penetration testing which will expose these flaws.

  • Peter Kalokathis 8 months ago

    Hi Akshay

    Why wouldn’t you simplify your code to the following?

    public override void Process(PreprocessRequestArgs args)
    {
    try
    {
    System.Collections.Specialized.NameValueCollection nameValues =
    HttpUtility.ParseQueryString(HttpContext.Current.Request.QueryString.ToString());
    base.Process(args);
    }
    catch (HttpRequestValidationException e)
    {
    throw;
    }
    }

  • akshaysuraadmin 7 months ago

    Thank you will look into it.

Add your comment

Your email address will not be published.