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. However if your trusted scripts attempt to load an image, a stylesheet, etc., then the
style-src directives still apply.
strict-dynamic directive was added to CSP Level 3. It is currenlty only supported in Chrome 52+ / Edge 79+ and Firefox 52+. It is unclear at this time when support for strict-dynamic will land in Safari.
Not supported at all in Internet Explorer