Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the correct way to load a script with the 'strict-dynamic' CSP directive?

Background

The idea of the Content Security Policy was to tell web-browsers what content to load from where. This means that attackers should not be able to inject their own code if, for example, 'unsafe-inline' was not explicitly allowed (which is not the best thing to do).

Google also released a CSP Evaluator, which is designed to find possible mistakes in your policy. With the default settings, the tool recommends using the 'strict-dynamic' policy for 'script-src'. The idea behind it is that you write a loader for whichever JavaScript sourcees you require and forbid everything else.

The Problem

What is considered the "correct" way to implement such a loader? Should the loader be written yourself (see below for example) or should a tool be used to create such a loader? (Please note that this question is not asking for a specific tool recommendation)

Example

var imported = document.createElement('script');
imported.src = '/path/to/imported/script';
document.head.appendChild(imported);

Context

My website currently has the following policy:

default-src 'none';
img-src 'self';
style-src 'self' https://stackpath.bootstrapcdn.com 'sha256-bviLPwiqrYk7TOtr5i2eb7I5exfGcGEvVuxmITyg//c=';
script-src https://use.fontawesome.com https://code.jquery.com https://cdnjs.cloudflare.com https://stackpath.bootstrapcdn.com;
base-uri 'none';
form-action 'none';
frame-ancestors 'none';

Google's tool suggested the following:

Host whitelists can frequently be bypassed. Consider using 'strict-dynamic' in combination with CSP nonces or hashes.

As such, I want to implement a loader to load these JS frameworks and I want to know how to best approach this issue.

like image 395
MechMK1 Avatar asked Jun 25 '18 13:06

MechMK1


1 Answers

An immediate answer is that as long as the script you're dynamically loading (/path/to/imported/script) is hosted in a domain that you've already whitelisted in script-src, you don't have to modify your CSP or change your loader -- everything will work as expected.

However, a broader problem is that your script-src whitelist includes domains that host Javascript which can be used by an attacker who finds a markup injection bug in your application to bypass your CSP. For example, https://cdnjs.cloudflare.com hosts Angular (https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.2/angular.min.js) which can be used by an attacker to convert an HTML injection into arbitrary script execution (here is a paper about this).

The suggestion in the CSP Evaluator tool is to switch your application to rely on a script-src which uses CSP nonces instead of the whitelist. To do this you would need to follow the process outlined at https://csp.withgoogle.com/docs/strict-csp.html -- basically, make sure that every <script> element has a correct nonce attribute which changes for every page load, or instead use CSP3 hashes for static scripts.

Your CSP would then look like:

... script-src 'nonce-[random-value]' 'strict-dynamic' 'unsafe-inline' https:; ...

If you use 'strict-dynamic', your script loader does not have to change because browsers will automatically trust scripts added to your page via programmatic APIs such as appendChild().

like image 89
Artur Janc Avatar answered Oct 04 '22 10:10

Artur Janc