top of page

Content Security Policy

  • Writer: Shounak Itraj
    Shounak Itraj
  • May 21, 2020
  • 6 min read

What is Content Security Policy?

Content-Security-Policy is a declarative mechanism that allows web authors to specify a number of security restrictions on their applications, to be enforced by supporting user agents. CSP is intended as “a tool which developers can use the lock down their applications in various ways, mitigating the risk of content-injection vulnerabilities and reducing the privigege with which their applications execute”

A CSP policy is delivered in the Content-Security-Policy Response Header or in a tag. The functioanlity of CSP can be categorized into following three:

Resource Loading restrictions: The most well-known and commonly used aspect of CSP is to limit the ability to load various subresources to a set of origins that are allowed by developer, known as source list.

Auxiliary URL-based restrictions: Along with the trusted subresources, some attacks can be prevented by mentioning trusted origin, with which the document interacts. For example, frame-ancestors directive, which defines the origins that are allowed to frame a document in order to prvent click jacking.

Miscellaneous confinement and hardening options: The directives upgrade-insecure-requests and block-all-mixed-content are used to block loading of mixed content and improve HTTPS support.

What CSP is used for?

CSP header allows developer to define approved/whitelisted source from which the web application can load sources. This protects visitors from whole range of issues as mentioned below:

XSS: The ability to inject and execute untrusted scripts in a vulnerable applications (This is protected with direcitves like script-src and object-src)

Clickjacking: Force user to take unwanted actions in your application by overlaying hidden frames on attacker controlled pages. (This is protected with frame-src and child-src) Mixed Content: Sometimes the website which is running on HTTPS protocols loads content in insecure HTTP protocol. (This is protected using the directive upgrade-insecure-requests and block-all-mixed-conten)

CSP Directives

CSP comes with a wide range of directives that can be used to enforce a policy across a load of content and circumstances. Following is the list of directives that are available:

default-src: The default policy for all resources if any of the directives are not defined (fallback)
script-src: Defin which scripts the protected resources can execute
object-src: Define from where the protected resource can load plugins
style-src: Define which styles the user applies to the protected resource
img-src: Define where the protected resource can load images
media-src: Define from where the protected resouce can load video and audio
frame-src: Define from where the protected resouce can embed frames
font-src: Define from where the protected resource can load fonts
connect-src: Define which URIs the protected resource can load using script interfaces
form-action: Define which URIs can be used as the action of HTML form elements
sandbox: Specifies an HTML sandbox policy that the user agent applies to the protected resouce
script-nonce: Define script execution by requiring the presence of the specified nonce on script elements
plugin-types: Define the set of plugin that can be invoked by the protected resouce by limiting the types of resources that can be embeded
report-uri: Specifies a URI to which the user agent sends reports about policy violation

Creating A Policy

For creating a policy you can be specific or broad. You can fine tune it so that it meets the requirements.

Content-Security-Policy: default-src https: This would allow any asset to be loaded over HTTPS from any origin

Content-Security-Policy: default-src yourwebapp.com This would allow any asset to be loaded from any origin on this domain using any scheme and port.

Content-Security-Policy: default-src https://yourwebapp.com:443 This would allow any assets to be loaded from this domain, over https and on port 443

Content-Security-Policy: default-src https://yourwebapp.com:* This would allow any assets to be loaded from this domain over https and any port

Wildcards can be used for the scheme, the port and left most part of hostname only.

*://*.yourwebapp.com:* This would match any scheme on any subdomain of yourwebapp.com, but not yourwebapp.com itself, and on any port.

Further to this, you can also use the following keywords alongside the ‘self’.

'none' blocks the use of any type of resource. 'self' matches the current origin (but not subdomains) 'unsafe-inline' allows the use of inline JS and CSS 'unsafe-eval' allows the use of mechamism like eval()

These can be applied like following: Content-Security-Policy: default-src 'none'; script-src https://yourwebapp.com This would allow javascript to be loaded from securityskeptic domain over https and will block other types of contents.

Content-Security-Policy: default-src 'none'; script-src https://yourwebapp.com; style-src 'unsafe-inline' This would be same as above just that it will allow inline stylesheets (CSS)

If you specify the directive twice with two different values, then second will be ignored.

There is no inheretenece from default-src

Content-Security-Policy: default-src: https:; script-src: http://yourwebapp.com This would result in no scripts being loaded over https from yourwebapp.com and will load over http

Correct policy will be

Content-Security-Policy: default-src: https:; script-src: https://yourwebapp.com http://yourwebapp.com

To Report the violation, along with blocking the loading of content report-uri directive is used. If this directive is used then browser POSTs a JSON formatted violation report to in the event it has to take a actoion on the CSP.

Content-Security-Policy: default-src https:; report-uri https://report.yourwebapp.com

The offending item:

The resulting report:

{
"csp-report": {
"document-uri": "https://yourwebapp.com",
"referrer": "",
"blocked-uri": "http://yourwebapp.com",
"violated-directive": "default-src https:",
"original-policy": "default-src https:;report-uri https://report.yourwebapp.com",
}
}

Breaking down the values in the report we have: document-uri: The page the violation occured on. referrer: The page’s referrer blocked-uri: The origin of the blocked URI violated-directive: The specific directive that was violated-directive original-policy: The entire policy

Real World Limitations

CSP works on basis of whitelisting origins of content using inline JS or CSS is considered unsafe. The very foundation of XSS attack is when an attacker finds a way to inject the script into the page. The typical XSS POC would look something like alert('xss') and being inline browser will execute the function alert. For this reason, inline JS or CSS are blocked by default and 'unsafe-inline' directive is used to allow inline scripts. If you dont allow inline JS, an attacker would be forced to try and load a script resource from another domain nd then have problems while loading as attacker domains will not be in whitelist.

To achieve this you need to externalize the tags. Instead of a block of code in your page, you create external file and reference it like instead. This also means inline event handlers like onClick"doStuff();" have to go and be replaced with addEventListener() calls instead. To allow inline JS or CSS with CSP effectiveness hash or nonce can be used. The basic premise of these two methods is to allow the use of inline scripts or styles and make CSP still effective.

Nonce

The policy to utilise a nonce value would look something like this:

Content-Security-Policy: script-src 'self' 'nonce-SomeRandomNonce'

Any inline script on the page that you wanted to be executed would use that value like:

...

This method is more suited to pages that are generated dynamically and requires the use of a sufficiently random and long nonce to prevent an attacker predicting the value for their own scripts. You can use the same nonce value for every script on the page, but it has to be re-generated and inserted into the header and all script elements on each response. A static nonce value would be useless.

Hash

The next method is to use hash of the script or style in the CSP header. More suited to static content, the browse will hash any inline JS or CSS and see if the digest matches a value found in the header. If it does, the content is safe for use.

Content-Security-Policy: script-src 'sha256-HashDigest'

The content of any tags on the page would then be hashed and compared to the value found in the CSP header. If the values matched the script would be allowed to execute.

The Problem

If scripts are dynamic and external resources have been loaded onto the page, it is not possible to use Nonce and Hash method. Then the policy can be as follows:

Content-Security-Policy-Report-Only: default-src https: 'unsafe-inline' 'unsafe-eval'

All this does is ensure that all content on the page will be loaded over a secure connection, or not loaded at all, preventing any mixed content warnings. It doesn’t offer any protection against XSS.

Browser Support

Fortunately, support for the CSP header is widespread but there is one thing to watch out for, Internet Explorer. The Content-Security-Policy header is supported in the latest and greatest versions of Chrome, FireFox, Safari (OSX and iOS), Opera (but not mini), the Android browser and Chrome for Android. Internet Explorere, however, requires X-Content-Security-Policy header instead. This means that if you want to have the most widespread support for your CSP header, you will need to issue it twice.

Recent Posts

See All
Port Scanner using Go Programming

Being in security industry we regularly need to write some simple scripts for automating few of our tasks like calling some APIs, parsing...

 
 
 

Comments


bottom of page