The CSP has two modes of operation : enforcing and report-only. The first one can be used to block and report attacks whereas the second one is used only to report abuses to a specific reporting server. In this blog post, we will focus only on the enforcing mode.
The policy, in order to work, has to be included in each HTTP response as a header (“Content-Security-Policy:”). The browser will then parse the CSP and check if every object loaded in the page adheres to the given policy. To specify these rules, the CSP provides different directives :
- object-src: defines valid sources of plugins, like <objects>
- img-src: defines valid sources of images
- style-src: defines valid source of stylesheets
- report-uri: the browser will POST a report to this URI in case of policy violation
Each of these directives must have a value assigned, which is usually a list of websites allowed to load resources from. The default behavior of directives if omitted, is to allow everything (“*”) without restrictions . A basic example of a valid CSP is shown below:
Content-Security-Policy: default-src 'self'; script-src compass-security.com
Misconfigurations and Bypasses
Even though it is possible to have a good level of control over the policy, errors in the definition of directives may lead to unexpected consequences. Misconfiguration or ambiguities can render the policy less efficient or easy to bypass. In addition, the functionality of the application could also be broken. The following example illustrates what can happen if “default-src” is omitted:
Content-Security-Policy: script-src compass-security.com
Now, all the scripts with source “compass-security.com” are allowed. But what about the other objects like stylesheets or flash applets? The policy above can be bypassed for example using this payload, which triggers an alert box using a Flash object:
<param name="AllowScriptAccess" value="always"></object>
Content-Security-Policy: default-src 'self'; script-src compass-security.com 'unsafe-inline';
This policy defines the default source as “self” and allows the execution of script from “compass-security.com” but, at the same time, it allows the execution of inline scripts. This means that the policy can be bypassed with the following payload :
Besides these trivial misconfigurations shown above, there are some other tricks used to bypass CSP that are less common and known. These make use, for example, of JSONP (JSON with padding) or open redirects. Let’s take a look at JSONP bypasses.
If the CSP defines a whitelisted JSONP endpoint, it is possible to take advantage of the callback parameter to bypass the CSP. Assuming that the policy is defined as follows:
Content-Security-Policy: script-src 'self' https://compass-security.com;
The domain compass-security.com hosts a JSONP endpoint, which can be called with the following URL:
The JSONP endpoint will then parse the callback parameter, generating the following response:
URLs with open redirects could also pose problems if whitelisted in the CSP. Imagine if the policy is set to be very restrictive, allowing only one specific file and domain in its “script-src” directive:
Content-Security-Policy: default-src: 'self'; script-src https://compass-security.com/myfile.js https://redirect.compass-security.com
At first sight, this policy seems to be very restrictive: only the myfile.js can be loaded along with all the scripts originating from “redirect.compass-security.com” which is a site we trust. However, redirect.compass-security.com performs open redirects through a parameter in the URL. This could be a possible option to bypass the policy :
Why is it possible to bypass the CSP using this payload? The CSP does not check the landing page after a redirect occurs and, as the source of the script tag “https://redirect.compass-security.com” is whitelisted, no policy violation will be triggered.
These are only a small subset of possible CSP bypasses. If you are interested, many of them can be found at  or .
The “nonce” directive
Besides the whitelist mechanism using URLs, in the CSP2 there are other techniques that can be used to block code injection attacks. One of these is represented for example by “nonces”.
Nonces are randomly generated numbers that should be defined in the CSP and included only inside <script> or <style> tags to identify resources and provide a mapping between the policy and the client’s browser. An attacker injecting a payload containing a script tag has no knowledge of the nonce previously exchanged between the client and the server, resulting in the CSP detecting this and throwing a policy violation. A possible configuration of a CSP with nonces could be:
Content-Security-Policy: script-src 'nonce-eED8tYJI79FHlBgg12'
The value of the nonce (which should be random, unpredictable, generated with every response, and at least 128 bits long ) is “eED8tYJI79FHlBgg12”.
This value should be then passed to each script tag included in our application’s pages:
<script src="http://source/script.js" nonce="eED8tYJI79FHlBgg12">
The browser will then parse the CSP, check if the scripts included have a matching value and block those that do not include any valid nonce. This technique works great against stored XSS, as the attacker cannot include valid nonces at injection time. Another advantage is that there is no need to maintain whitelists of allowed URLs, as the nonce acts as an access token for the <script> tag and not necessarily for the source of the script. It is also possible to use hashes in order to identify the content of each <script> element inside the page, more information about this feature can be found at .
We have seen that the CSP is a very useful tool web developers can use to have better control on the loaded resources. The different directives provide flexibility to allow or deny potentially dangerous web resources inside web pages. However, it is also easy to make errors if too many URLs are whitelisted (e.g. hidden JSONP endpoints). Here at Compass we encourage the use of the CSP as an additional barrier against web threats. Nonetheless, I would like to stress that the first protection against code injection should always be provided by a solid input/output validation, which can help also against other common attacks like SQL injections.
If you would like to get more information about how web applications should be protected, or you want to deepen your web security knowledge we provide different trainings:
We are also offering trainings in other areas of IT Security. You can check the different topics here:
Sources & References