Content Security Policy (CSP) explained including common bypasses


We have written about Content Security Policy (CSP) on Detectify Labs before. But maybe you’re wondering why should you have it on your site to begin with? This article will explain why having CSP can prevent header exploits and includes attributes and common bypasses.

CSP is a response header that instructs the web browser from what sources it is allowed to include and execute resources from. It is considered additional protection to minimize the damage if an attacker would find a XSS-vulnerability on your web site. Having this allows you to specify different sources for different media types. It is possible to specify one domain that images can be embedded from, two other domains where stylesheets are stored and that scripts can only be loaded from the domain itself.

There are a few options in addition to domains as well.

CSP do not prevent HTML-injection. There are no external resources and HTML is normally not limited by CSP (compared to inline script). In browsers that supports it HTML-injection can be used to set cookies, as you can make a set-cookie meta tag in HTML. HTML-injection could also be used for phishing, and as it is executed on the original domain password managers and the browsers built-in save-password function might automatically fill populate the password field.

CSP also does not prevent data leakage or extraction. It does indeed prevent external resources, but there are a few HTML-tags that will allow external requests but at the same time are not covered by the CSP.

Example policy

Content-Security-Policy: default-src 'self'; img-src *; media-src media1.com media2.com; script-src userscripts.example.com

Sourced from Mozilla.

The policy sets the default-src to self, meaning that for media types that do not have anything else specified they can only be loaded from the same origin. Images on the other hand can be loaded from anywhere, and audio-video tags only from media1.com and media2.com.

You are able to even further narrow down the allowed sources by path in addition to domain. The example CSP  https://www.cspvalidator.org/ is a great example of this. When done properly, this would prevent most of the bypasses described later in this article.

A more full list can be found here but the following are the good-to-knows. These are specified in the CSP the same way that you would specify a domain.

self

‘self’  means that the page is allowed to include resources from itself. Without it, would fail because the source would not be allowed.

Example policy:

Content-Security-Policy: default-src 'self' cdn.example.com

inline

Inline scripts look like this compared to eg., which is a reference to an external file. This is enabled by including unsafe-inline in the CSP-policy.

Allowing this makes the CSP a much weaker protection against XSS-attacks, and is why its name is prefixed by unsafe. Having to type unsafe should be a reminder that you are doing something potentially dangerous.

This also includes event-handlers. Assuming you want to avoid having to implement unsafe-inline you need to change:

to:

document.getElementById("btn").addEventListener('click', doSomething);

Sourced example from Mozilla – CSP Script-src.

Not allowing inline script will also prevent links with Javascript as protocol, eg. example.

If you must allow inline-scripts one option is to use a nonce or hash the content. This way you are able to allow specific script snippets while still preventing XSS.

Example policy:

Content-Security-Policy: default-src cdn.example.com; script-src 'unsafe-inline' 

eval

Even when Javascript is allowed, having a CSP will disallow a few functions that are considered dangerous. Those can be enabled again with unsafe-eval (once again, having to type unsafe is meant as a remainder what you are doing is dangerous, and should be avoided if possible).

It is common to use eval and similar functions in dangerous ways and most often possible to write code that does not need them. Unfortunately, if you are applying a CSP to an existing web page it might be needed in the beginning to not break existing code. This also go for third-party Javascript libraries.

Example policy:

Content-Security-Policy: default-src cdn.example.com; script-src 'unsafe-inline'

A good thing to know when implementing a policy is that there is an attribute for generating reports, so the web browser can report back to the server when it is blocking something. This will allow you to discover where you might have implemented the policy faulty or where you need to change the code of the website. It could also help you discover active XSS-attacks that are done at scale.

This is done by adding report-uri and report-to to the policy, and more information on how exactly can be found here. Report-uri is now deprecated and you should move to report-to, but as the latter is yet to be supported in every browser you are recommended to implement both during the transaction period.

It is possible to implement a CSP in a report-only way, meaning it will actually not block anything but only create reports. This allows you to ensure everything is implemented directly before risking to break any existing functionality. To do this, simply use the name Content-Security-Policy-Report-Only instead of Content-Security-Policy for the header.

Callback

Let’s assume that you allow any script file from example.com to be included on your site. Now, if example.com has a JSON-endpoint, where a user is able to control part of the code this might lead to a problem.

Request:

example.com/api?callback=test

Response:

test("example")

Request:

example.com/api?callback=alert(document.domain);test

Response:

alert(document.domain);test("example")

For your own domain, you are responsible for making sure there are no such endpoints. However, when you allow external domains in the policy it makes it harder, as some very legitimate domains have those issues. One way to limit the risk of this is narrowing down the allowed domain with path, as described earlier (see Example policy).

The problem is that there are no real impacts of example.com to have this JSON-endpoint, and it mostly affects sites that have them in the CSP. Because of this, it is sometimes hard getting them to fix those issues. An example of this is when there was a CSP bypass on twitter. 

CDN – anyone can upload files

It is common to upload files to a domain such as Amazon S3 and then allowing the whole S3 domain in the CSP, without realizing that anyone else can also upload files to the same domain. This would make the CSP somewhat useless in a security aspect.

This also goes for other web services, not only CDNs. If example.com had a file uploading function, the same issue would occur again.

CDN – abusing existing libraries

There are CDN-hosts that hosts a limited amount of existing libraries. Allowing such host means that an attacker is able to include any other library. For example, in the case they are able to include angular.js, this could be used to bypass the CSP.

Injection in the actual policy

If the policy reflects part of the request, it might be possible for the attacker to actually modify the header value. This might give the attacker the ability to inject their own policies. Even when that is not possible, just making sure it generates a syntax error is enough to make the CSP useless in Edge.

See more about that technique here on Portswigger.

Make sure you have applied the policy to every page, including error pages. If a policy is not applied to a page under your domain, even though that is not where the XSS/injection happens, it could be used to bypass the policy.

See more about that technique here on Wallarm.

How can Detectify help:

You can follow this guide to add secure headers, and for those who like automation, you can use an automated scanner like Detectify to check your web applications for various response header vulnerabilities. Give it a try and get your free scan here and see whether your headers are making your website vulnerable.

Detectify is automated web application scanner checking for 1000+ known vulnerabilities including OWASP Top 10 and SSRF. Start your Detectify free trial today to see whether your applications are missing HTTP headers and more.



Source link