Sitecore Security #3: Prevent XSS using Content Security Policy
This is not a write-up on the complete CSP specification, there are other great sources for that on the web, I included them at the end of the article.
The module will be available on the marketplace when it has passed quality control. Sourcecode is available on: https://github.com/BasLijten/SitecoreSecurity
The danger of XSS attacks – some scenarios
From a business perspective, this is a situation that you don’t want to appear on your site. The complete site could even be defaced.
I even showed this off during my SUGCON presentation – Sitecore might be secure, but your site isn’t:
Thanks for all positive reactions on my #sugcon #sitecore #security session. As a reward, here the picture I took! pic.twitter.com/l6FTJI4SHO— Bas Lijten (@BasLijten) April 25, 2016
Worse things happen, when other parts of your security aren’t in place as well, for example, secure cookies (when working over HTTPS and yes, you should always do that), http-only cookies or session management. I showed off a scenario at the SUGCON where session fixation was possible, due to an XSS vulnerability in combination with bad session management. In this case, Bobby Hack (identity: extranet\robbert) was able to view personal details of me, Bas Lijten:
What did these hacks have in common?
A very simple, yet effective way to prevent reflected XSS attacks, is to apply correct input and output validation. Don’t trust your external actors, never! But when that line of defense is broken, or some external service that you use has a broken security layer, other defensive mechanisms have to come in place. This is also known as “defense in depth”: never rely on a single line of defense.
How can the content security policy help in here?
With the CSP, policies can be defined on what kind of resource is allowed, how is it allowed and what sources are trusted? The resources are split amongst different categories, for example, default (your fallback/main policy), script, images, styling, et cetera. Per resource different options can be applied:
|None||Prevents loading resources from any source|
|All||Allows all options|
|Self||Allows loading resources from ‘same-origin’|
|Data||Allows loading resources via de the data scheme (base 64 encoded images)|
|Unsafe-Inline||Allows the use of inline-elements; style, onclick, script tags, et cetera|
|Hosts||The external hosts that are allowed to load content from|
Content-Security-Policy: default-src 'none' ; script-src 'self' https://*.googleapis.com; style-src 'self' 'unsafe-inline' ;
Please note that all major browsers support the content security policy header, some in the form of the normal header, some need the X-Content-Security-Policy headers. Some browsers do not support all resources as well.
Creating a CSP
To create a CSP by hand can be very time-consuming. You’d need to know about the exact specifications (a script policy contains other parameters than a CSS policy, while the referrer section looks completely different). Is the option ‘none’ with or without quotes, is the option ‘self’ with or without quotes? How to specify the allowed hostnames? Scott Helme, security specialist, created the website report-uri.io, on which he hosts security tools and one of them is to create those CSP’s. Go play around with it and see how stuff works ;).
For Sitecore, I created a module to do this, as multiple policies may need to be served and maintained per site. These CSP’s are manageable from content without too much effort, more on that later
Testing a CSP
When configuring a CSP, the policy can be created and be applied to the page. The next image contains the out of the box Sitecore landing page, with the following CSP applied.
Content-Security-Policy:default-src 'none' ;script-src 'none' ;style-src 'none' ; img-src 'none' ;font-src 'none' ;connect-src 'none' ;media-src 'none' ;object-src 'none' ; child-src 'none' ;frame-ancestors 'none' ;form-action 'self' ;manifest-src 'none' ;
One of the lessons learned: Misconfiguring the CSP can seriously damage your site! The good thing is, that the Console exactly shows what is going wrong:
While this information can be used to test and modify existing policies, it’s not convenient to do this with a broken site. Luckily, there is a solution for this one: The Content-Security-Policy-Report-Only header. When the same policy is used with this header and the original CSP is deleted, the site will still work (unprotected!), while the new policy can be tested:
A mixture of a CSP and CSP-Report-Only will work together: Using this mixture, your site remains protected, while the modifications can be tested. Of course, different pages, with different policies will behave differently on different browsers (and how many times can the word ‘different’ be used in one sentence? I need to differentiate more ;)). See Akshay’s blogpost on the browser differences for more info! This can be pretty hard to test and monitor in different circumstances. And of course, there is a solution to test and monitor these policies.
Reporting CSP violations
To monitor violations (which can be malicious, or might be due to an error) is not too hard: the CSP specification contains a report-uri field which can be used to send to violations to. The website report-io, which I mentioned earlier, can also be used as endpoint to collect the CSP violations. I configured my site to report it to this service:
In this specific example, some enforced policies are shown (a filter on report-only didn’t work, as I didn’t have any report-only errors at the time). The first policy which is shown, shows a violation on the script-src resource policy: because of the use of the unsafe eval function, this violation happened. Another example is the 4th one, where an image violation has taken place. I configured my policy to only allow images from my own domain, while the site tried to load images from an external domain.
Seeing a CSP in action!
When the CSP is applied, this leads to the following behavior: the requests to the domain that is not whitelisted get blocked by the CSP. This mitigation prevented a malicious user from taking a picture of me.
Introducing Convenient Content Security Policy for Sitecore
While most blogposts on the internet learns us how to configure IIS to use CSP (by adding a header in the web.config), this doesn’t work too well for Sitecore. Each page might need another CSP (although I wouldn’t recommend that one) and how would a multi-site setup be configured? Would every CSP have to be created on an external site, copied over, verified, published, et cetera? While this would work for the first times, this wouldn’t work over time.
I created a template which contains all of the CSP 1.0 and 2.0 options (yes my friends, next surprise, there are multiple versions ;). Using this template, separate policies can be created:
Another template, the Content Security Policy link, which contains the CSP Link and the CSP Report Only link, can be used as one of the base templates of a page ( I would prefer to have one single base content page template to which all the generic templates can be assigned). This results in the addition of two extra fields on your pages:
Using this mechanism, CSP’s can be reused easily, be put on standard values, be updated easily, et cetera! This results in the following extra response headers in your request.
This module adds the X-Frame-Options header as well, based on the frame-ancestor setting for your CSP. It should lead to the same result, so it’s no use to configure this one separately and possibly differently. This would lead to strange browser behavior. Especially with the introduction of the X-Frame-Options header in Sitecore 8.1 update 3 – out of the box the X-Frame-Options: SAMEORIGIN header would be send in the response: this would conflict with this CSP policy.
The Content Security Policy header is an excellent mechanism to defend against XSS and other code injection attacks. While the CSP itself can be quite big, confusing and even break your site, there are several tools and patterns to aid you in the journey to a safe website. With the introduction of the Sitecore Security module, the CSP’s can even be managed from within your content on a per-site or even per-page basis!