Content Security Policy (CSP)
Quick Reference Guide


strict-dynamic in CSP

The strict-dynamic source list keyword allows you to simplify your CSP policy by favoring hashes and nonces over domain host lists.

A strict-dynamic Example

Here is an example Content-Security-Policy that uses strict-dynamic:

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.

Dealing with Unsupported Browsers

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:

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 https://cdn.example.com/some-script-you-need.min.js

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.

What directives support strict-dynamic?

You can use strict-dynamic in a script-src or default-src directive. When it is in the default-src it only applies to loading of scripts.

What about CSS or Images Loaded via strict-dynamic JavaScript?

If one of your trusted scripts loads JavaScript using a safe method (document.createElement), then it can load arbitrary scripts with strict-dynamic. However if your trusted scripts attempt to load an image, a stylesheet, etc., then the img-src, and style-src directives still apply.

Browser Support for strict-dynamic

The 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