trusted-types
Directivetrusted-types
Content Security Policy (CSP) directive is typically used in conjunction with the require-trusted-types-for
CSP directive to instructs the browser to require the use of trustedTypes
when passing a string to an unsafe DOM sink (such as innerHTML
).
The trustedTypes
JavaScript api was implemented in Chrome & Edge in 2020 which lets developers mark HTML as trusted before passing it to a dangerous sink within the DOM api, such as innerHTML
or document.write
. The require-trusted-types-for
CSP directive requires that the trustedTypes API is used, while the trusted-types
directive limits the names of the policies in use.
HTML is marked as TrustedHTML
via the createHTML
function of the policy. You can also use createScriptURL()
to create a TrustedScriptURL
object, or createScript()
to create a TrustedScript
object.
Here's our old unsafe code:
untrusted_data = "123"; unsafe_html = '<div class="wrapper">' + untrusted_data + '</div>'; element = document.getElementById('content'); element.innerHTML = untrusted_data;
Now here's how we might rewrite this in a way that is safe (by using innerText), and also marking it as TrustedHTML:
untrusted_data = "123"; myPolicy = trustedTypes.createPolicy("myPolicy", { createHTML: function(input) { var div = document.createElement("div"); div.classList.add('wrapper'); if (input.match(/^[0-9]+$/)) { div.innerText = input; } else { div.innerText = "0"; } return div.outerHTML; } }); element = document.getElementById('content'); element.innerHTML = myPolicy.createHTML(untrusted_data);
In this example the call to myPolicy.createHTML(untrusted_data)
returns a TrustedHTML
object.
It is certainly possible to create policies that are not actually safe, here we can take our old code and create an unsafe policy. We didn't improve security in this example, we are only bypassing the CSP restriction.
untrusted_data = "123"; myUnsafePolicy = trustedTypes.createPolicy("myUnsafePolicy", { createHTML: function(input) { return '<div class="wrapper">' + input + '</div>'; } }); element = document.getElementById('content'); element.innerHTML = mySanitizerPolicy.createHTML(untrusted_data);
The trusted-types
directive is used along with the require-trusted-types-for
directive.
Content-Security-Policy: require-trusted-types-for 'script';trusted-types myPolicy
In this example we are requiring the use of trusted types via the require-trusted-types-for
directive, and then limiting the list of allowed trusted type policies with the trusted-types
directive.
In this example only myPolicy
may be used, even if we attempt to define myUnsafePolicy
it will not be allowed.
In fact, we will actually get two errors now:
Refused to create a TrustedTypePolicy named 'myUnsafePolicy' because it violates the following Content Security Policy directive: "trusted-types myPolicy"
And we will get this error caused by the trustedTypes.createPolicy("myUnsafePolicy", ...)
line.
Uncaught TypeError: Failed to execute 'createPolicy' on 'TrustedTypePolicyFactory': Policy "myUnsafePolicy" disallowed
It is possible that a malicious script could create its own unsafe policies, so by listing the policies you are denoting these policies as safe and trusted within your application to sanitize HTML, create scripts or create script urls.
Some JavaScript Frameworks provide built-in support for Trusted Types.
Angular has had built-in support for Trusted Types since Angular 11. If you use Angular or you'll need to add the trusted type named angular
to your CSP trusted-types
directive when using the require-trusted-types-for 'script'
directive.
In addition to the angular
type there are a few other built-in trusted type policies. If your Angular Application uses any of the bypassSecurity functions such as bypassSecurityTrustHtml
then you'll need to add angular#unsafe-bypass
to your trusted-types
list. Additionally angular may define the policies: angular#bundler
, angular#unsafe-jit
and angular#unsafe-upgrade
depending on features used.
The DOMPurify HTML sanitizer library can return TrustedHTML objects by passing RETURN_TRUSTED_TYPE: true
into the sanitize function. For example:
DOMPurify.sanitize(input, {RETURN_TRUSTED_TYPE: true})
DOMPurify will create a policy named dompurify
by default. You can customize this policy name by adding the attribute data-tt-policy-suffix
to the Script element used to load DOMPurify. If you had data-tt-policy-suffix="mysuffix"
then the policy would be named dompurify#mysuffix
You could also create your own trusted types policy that uses DOMPurify like this:
if (window.trustedTypes && trustedTypes.createPolicy && DOMPurify) { trustedTypes.createPolicy("default", { createHTML: (input) => DOMPurify.sanitize(input, {RETURN_TRUSTED_TYPE: false}) }); }
In the above example the name of the trusted types policy created is called default
.
trusted-types
Note, a trustedTypes polyfill is available from the w3c, but the require-trusted-types-for
directive and the trusted-types
directive will still be ignored.
Want to learn the ins and outs CSP? Grab a copy of the CSP Developer Field Guide. It's a short and sweet guide to help developers get up to speed quickly.
Grab a CopyAdvisory Week is a weekly roundup of all the security advisories published by the major software vendors.