require-trusted-types-for
Directiverequire-trusted-types-for
Content Security Policy (CSP) directive 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. This api allows developers to mark HTML as trusted before passing it to a dangerous sink within the DOM api, such as innerHTML
.
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.
The following JavaScript sets the innerHTML
property of an element
untrusted_data = "anything, could be result of an api fetch"; element = document.getElementById('content'); element.innerHTML = untrusted_data;
The require-trusted-types-for
directive only has one additional argument, which is the realm for which trusted types are required. Currently 'script'
is the only supported value for the realm. As a result the require-trusted-types-for
header or meta tag will look like this:
Content-Security-Policy: require-trusted-types-for 'script';
When we enable such a CSP policy, the above code which attempts to unsafely set the innerHTML
property of a DOM element, will now fail with an error that looks like this:
Uncaught TypeError: Failed to set the 'innerHTML' property on 'Element': This document requires 'TrustedHTML' assignment.
If we were to use document.write(untrusted_data)
, then you'd hit an error like this:
Uncaught TypeError: Failed to execute 'write' on 'Document': This document requires 'TrustedHTML' assignment.
When you see This document requires 'TrustedHTML' assignment., then you can be pretty sure it is due to the require-trusted-types-for
and / or trusted-types
CSP directives.
The trustedTypes
API allows you to create a sanitizer policy which can sanitize the HTML input (among other things). When you use the trusted types API you pass in a string of untrusted data, and are returned an object of type TrustedHTML
. So when the trusted types api is in use you would pass a TrustedHTML
object instead of a string into the innerHTML
, or document.write
or any of the other unsafe DOM sinks.
if (window.trustedTypes && trustedTypes.createPolicy && DOMPurify) { trustedTypes.createPolicy("default", { createHTML: (input) => DOMPurify.sanitize(input, {RETURN_TRUSTED_TYPE: false}) }); }
This default policy runs everything through DOMPurify (a third party library designed to sanitize HTML to mitigate XSS potential). You'll need to load in that library before running the above script or it will be skipped.
Malicious code could certainly create its own policy, or even use a policy defined by another library for a different purpose.
By using the trusted-types
CSP directive you can actually specify which named policies you allow.
require-trusted-types
Note, a trustedTypes polyfill is available from the w3c, but the require-trusted-types-for
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.