Here is an example
Content-Security-Policy that uses
script-src 'nonce-r@nd0m' 'strict-dynamic';default-src 'self';
Now we can simply use a nonce to load our scripts:
<script src="/script-loader.js" nonce="r@nd0m"></script>
The key super power of
strict-dynamic is that it will allow
/script-loader.js to load additional scripts via non-"parser-inserted" script elements.
So how do you create a non-"parser-inserted" script element? Here's an example:
var s = document.createElement('script'); s.src = "https://cdn.example.com/some-script-you-need.min.js"; document.body.appendChild(s);
You can also use other mechanisms to create a script loader, such as webpack, RequireJS, head.js, yepnope.js, etc.
Since this is a new feature of CSP (CSP Level 3), if someone is using an older browser that may only have CSP Level 2 support, using the above policy the request to load a script from
cdn.example.com would be blocked. Support for nonce would still work in CSP Level 2 browsers, but not in CSP Level 1.
Thankfully the authors of CSP Level 3 considered this, and have a clever workaround. When
strict-dynamic is used, browsers that support it will ignore the following source list expressions:
https:host based source lists
In fact you might see something like this in your developer tools console:
content security policy: ignoring “'unsafe-inline'” within script-src: ‘strict-dynamic’ specified
content security policy: ignoring “http:” within script-src: ‘strict-dynamic’ specified
content security policy: ignoring “https:” within script-src: ‘strict-dynamic’ specified
content security policy: ignoring “'unsafe-eval'” within script-src: ‘strict-dynamic’ specified
So our script can be made backwards compatable by doing something like this:
script-src 'nonce-r@nd0m' 'strict-dynamic' https: 'self';default-src 'self';
Above we have added 'self' to allow loading of
/script-loader.js and we have added
https: to allow loading of
You may notice that by adding
https: we are allowing any domain to load a script, you could be more specific if you wanted to. In our example the following would be better:
script-src 'nonce-r@nd0m' 'strict-dynamic' cdn.example.com 'self';default-src 'self';
If we had an inline script block then we could consider adding
'unsafe-inline' to the policy to allow it to load on CSP Level 1 Browsers. You'll need to balance the compexity of your policy vs the bredth of browsers that you want to support.
On older browsers you may see something like this:
the source list for content security policy directive 'script-src' contains an invalid source: ''strict-dynamic''. it will be ignored.
You can also ignore such a message.
strict-dynamic directive was added to CSP Level 3. It is currenlty only supported in Chrome and Firefox.
It is not supported at all in Internet Explorer, you need to use the Edge browser instead.