As a website owner, it’s a good idea to be aware of the security issues that might affect your site. For example, Cross-site Scripting (XSS) attacks consist of injecting malicious client-side scripts into a website and using the website as a propagation method.
You probably know too that client-side scripts can be programmed to do pretty much anything. They can be as simple as showing an alert message in your website, to animating images, mining cryptocurrencies or showing pop-ups that contain NSFW pharma products.
Injecting Malicious Scripts in Vulnerable Websites
It’s important to understand that when attackers find a website vulnerable to XSS attacks, they have two options of injecting malicious scripts into it:
- Inline script: when attackers put their code directly into your website’s HTML.
- Load script from an external domain: when attackers load a script from multiple infected sites and modify the script when they need to. All the changes will be reflected on those sites.
Loading scripts from an external domain is the preferred method by attackers.
XSS attacks are possible because browsers trust all requests that come from your website, inline, or from an external source. This post aims to introduce you to a tool that can help you mitigate some of the risks of XSS attacks.
Content Security Policy
According to W3’s website, the Content Security Policy (CSP) is:
A tool which developers can use to lock down their applications in various ways, mitigating the risk of content injection vulnerabilities such as cross-site scripting, and reducing the privilege with which their applications execute.
A CSP does this by allowing web developers to define directives such as:
- Execute all code coming from my domain (e.g awesomedomain.com)
- Execute all code coming from an external trusted domain and subdomains (e.g *.trusteddomain.com)
- Execute nothing except for the script awesomedomain.com/script.min.js
- Show only images coming from cdn.securecdn.com
- A mix of the past examples and much, much more!
Firefox will respect the second version of the CSP since version 31, Chrome since version 40, and Safari since version 10. Browsers that don’t support it will simply ignore it.
Defining and Delivering a CSP
Every CSP is made of two parts:
- The first part is a set of directives which tell the browsers of your website’s visitors how to control specific resources in your website.
- The second part is a disposition which tells browsers whether to enforce the CSP or not.
We will talk about the disposition of a CSP later in the post.
Content-Security-Policy: script-src 'none'
Now that we’ve created one directive, let’s stop for a moment and see how we can deliver it to the browser of your website’s visitors. You have two options:
The first option is to use the HTMLtag, which should be placed as early as possible in the HTML of your web pages.
<meta http-equiv="Content-Security-Policy" content="script-src 'none';">
The second method is to use a Content-Security-Policy HTTP Response Header.
For example, if you use Apache, you can define the CSP in the httpd.conf, VirtualHost, or .htaccess file of your site.
Header set Content-Security-Policy “script-src 'none';”
The second method is considered to be more secure and, in fact, the W3 itself recommends serving CSPs this way.
Examples of Policies
First of all, let’s see some of the directives we can define in our policies:
- script-src will restrict the location from which scripts are executed (it will also block inline scripts and the eval() function).
- media-src will restrict the location from which video, audio, and associated text track resources are loaded.
- frame-src will restrict the location from which iFrames are loaded.
- img-src will restrict the location from which images are loaded.
- font-src will restrict the location from which font files are loaded.
- style-src will restrict the location from which .css files are loaded (and also block inline styles).
- default-src will apply a security policy to child-src, connect-src, font-src, frame-src, img-src, manifest-src, media-src, media-src, object-src, script-src, style-src and worker-src where they themselves are undefined (will save you typing!).
You can see the complete list of directives you can set on W3’s website.
Second, let’s see some of the keywords/values you can set your directives to:
- ‘self’ will match the current URL’s origin (the URL of your website).
- ‘https://*’ will match all resources loading over HTTPS.
- ‘*.awesomedomain.net’ will match the domain awesomedomain.net and all subdomains
‘https://awesomedomain.net/script.js’ will only match the script script.js in the domain awesomedomain.net over HTTPS.
Let’s now see a few concrete examples.
Content-Security-Policy: script-src 'self'
Content-Security-Policy: script-src 'self'; img-src ‘self’;
Content-Security-Policy: script-src 'self' cdn.trustedorigin.net; img-src *;
CSP blocking iFrames in your site
Content-Security-Policy: frame-src ‘none;’
CSP blocking all form submissions in your site
Content-Security-Policy form-action 'none';
CSP only allowing the file script.js on https://trustedorigin.net/ and default the values of child-src, connect-src, font-src, frame-src, img-src, manifest-src, media-src, media-src, object-src, script-src, style-src and worker-src to the current URL’s origin
Content-Security-Policy default-src ‘self’; script-src https://trustedorigin.net/script.js;
Testing the CSP
As we mentioned before, it’s important to know that every policy has a disposition, which is either “enforce” or “report“.
The disposition “enforce” applies the CSP, while the “report” one allows developers to experiment with the policy without actually enforcing it.
You can do this by defining the Content-Security-Policy-Report-Only header instead of the Content-Security-Policy header, and adding the directive report-uri with a URL where you would like to see reports about CSP violations.
The idea here is that you can fix any accidental violation to your policy before enforcing it.
Content-Security-Policy-Report-Only header is not supported inside an element.
Fixing Mixed Content Warnings with a CSP
You can address the problem of Mixed Content Warnings with CSP by defining the upgrade-insecure-requests directive, that gets to do all the heavy work for you.
When you use upgrade-insecure-requests in your CSP, all HTTP requests are upgraded to HTTPS by the browser before carrying out network requests.
If in your website you have something like this:
It will be requested as if this were this:
<img src="”https://awesomedomain.net/image.jpg”" />
You can also go one step further and add the following directive to your CSP:
As the name of the directive implies, it will block all content that is not accessible through HTTPS.
Both the upgrade-insecure-requests and the block-all-mixed-content directives were thought to maintain the security of your site, hence, they will block resources not available over HTTPS. Careful with these directives though, as they can break your site.
Please, remember that browsers not respecting the CSP of your site will still display Mixed Content Warnings on your site. This should not be considered a complete fix for the problem. You can learn more about how to solve the root problem of Mixed Content Warnings in this blog post and our free guide on How to Install an SSL Certificate.
XSS attacks can be extremely harmful to an online business. The injection of unwanted malicious scripts can get your website blacklisted by Google or other blacklist authorities, and, consequently, hurt your business’s reputation.
It’s very important to understand that a CSP will not stop attackers from exploiting vulnerabilities in your website. But it does stop modern browsers from executing injected malicious scripts if they are ever injected into your site. You should consider the CSP as another layer of protection around your website, not as the only line of defense.
If you are looking for a complete website security solution that will monitor and protect your website, we offer a Website Security Platform.