Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

This document requires 'TrustedScriptURL' assignment

After adding require-trusted-types-for 'script'; in my Content-Security-Policy header, which introduced from Chrome 83 Beta to help lock down DOM XSS injection sinks,

when I open my website, it becomes a blank page. I got many these three kinds of errors in my console. (Chrome version 83.0.4103.61)

This document requires 'TrustedScript' assignment.

This document requires 'TrustedScriptURL' assignment.

TypeError: Failed to set the 'src' property on 'HTMLScriptElement': This document requires 'TrustedScriptURL' assignment.

I have read the article Prevent DOM-based cross-site scripting vulnerabilities with Trusted Types. However, the article only says how to handle TrustedHTML, but not TrustedScript or TrustedScriptURL.

Any guide will be helpful. Thanks!

like image 564
Hongbo Miao Avatar asked May 29 '20 07:05

Hongbo Miao


2 Answers

We have been running into the very same problem.

Here's how you fix it:

  1. Install the DOMPurify library. npm install --save DOMPurify

  2. Create a file trusted-security-policies.js.

  3. In the entry point for your bundler (like e.g. webpack), import this file first (before any code that potentially violates the content security policy):

    import './path/to/trusted-security-policies';
    
import DOMPurify from 'dompurify';

if (window.trustedTypes && window.trustedTypes.createPolicy) { // Feature testing
    window.trustedTypes.createPolicy('default', {
        createHTML: (string) => DOMPurify.sanitize(string, {RETURN_TRUSTED_TYPE: true}),
        createScriptURL: string => string, // warning: this is unsafe!
        createScript: string => string, // warning: this is unsafe!
    });
}

What this does: Whenever a string is assigned to be parsed as HTML, or as a URL, or as a script, the browser automatically passes this string through the defined handler function.

For HTML, the HTML is being sanitized from potential XSS code by the DOMPurify library.

For scriptURL and script, the string is just passed through. Please note that this effectively disables security for these two parts and should only be used for as long as you haven't identified how to make these strings safe yourself. As soon as you have that, replace the handler functions accordingly.


Edit, December 2021: I was able to contribute to DOMPurify so the library now also can be configured to work if you have the need to use custom elements in your HTML strings, as well as custom attributes (which prior to release 2.3.4 were simply removed in the sanitization process):

/**
 * Control behavior relating to Custom Elements
 */
 
// DOMPurify allows to define rules for Custom Elements. When using the CUSTOM_ELEMENT_HANDLING 
// literal, it is possible to define exactly what elements you wish to allow (by default, none are allowed).
//
// The same goes for their attributes. By default, the built-in or configured allow.list is used.
//
// You can use a RegExp literal to specify what is allowed or a predicate, examples for both can be seen below.
// The default values are very restrictive to prevent accidental XSS bypasses. Handle with great care!


var clean = DOMPurify.sanitize(
    '<foo-bar baz="foobar" forbidden="true"></foo-bar><div is="foo-baz"></div>',
    {
        CUSTOM_ELEMENT_HANDLING: {
            tagNameCheck: null, // no custom elements are allowed
            attributeNameCheck: null, // default / standard attribute allow-list is used
            allowCustomizedBuiltInElements: false, // no customized built-ins allowed
        },
    }
); // <div is=""></div>
 
var clean = DOMPurify.sanitize(
    '<foo-bar baz="foobar" forbidden="true"></foo-bar><div is="foo-baz"></div>',
    {
        CUSTOM_ELEMENT_HANDLING: {
            tagNameCheck: /^foo-/, // allow all tags starting with "foo-"
            attributeNameCheck: /baz/, // allow all attributes containing "baz"
            allowCustomizedBuiltInElements: false, // customized built-ins are allowed
        },
    }
); // <foo-bar baz="foobar"></foo-bar><div is=""></div>
  
var clean = DOMPurify.sanitize(
    '<foo-bar baz="foobar" forbidden="true"></foo-bar><div is="foo-baz"></div>',
    {
        CUSTOM_ELEMENT_HANDLING: {
            tagNameCheck: (tagName) => tagName.match(/^foo-/), // allow all tags starting with "foo-"
            attributeNameCheck: (attr) => attr.match(/baz/), // allow all containing "baz"
            allowCustomizedBuiltInElements: true, // allow customized built-ins
        },
    }
); // <foo-bar baz="foobar"></foo-bar><div is="foo-baz"></div>
like image 149
connexo Avatar answered Oct 04 '22 14:10

connexo


Check this. MIght help you out.

https://zeronights.ru/wp-content/themes/zeronights-2019/public/materials/3_ZN2019_Jakub_Vrana_Krzysztof_Kotowicz_Trusted_Types_and_the_end_of_DOM_XSS.pdf

References for a potential fix:

  • https://github.com/w3c/webappsec-trusted-types
  • https://w3c.github.io/webappsec-trusted-types/dist/spec/#trused-script-url

Background on Trusted Types and Chrome browser implementation:

  • https://github.com/w3c/webappsec-trusted-types/blob/master/explainer.md
  • https://www.chromestatus.com/feature/5650088592408576
  • https://gadgets.kotowicz.net/poc/Trusted_Types_TPAC_2018.pdf

Short-term fix option:

  • Add a report-only CSP header. [not great and you have to knowledge various risks if you are running a sensitive prod app]

Long term fix option:

  • You could investigate to bring to your base the external third party stuff and avoid the overall pain.

I am not an expert, just trying to learn from this too and I'd say the fix is pretty much from case to case, and not a silver bullet type.

All the best!

like image 24
Chris Smith Avatar answered Oct 04 '22 13:10

Chris Smith