Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Required resources blocked by Trusted-Types CSP #1334

Closed
Black-Platypus opened this issue Sep 24, 2021 · 9 comments
Closed

Required resources blocked by Trusted-Types CSP #1334

Black-Platypus opened this issue Sep 24, 2021 · 9 comments

Comments

@Black-Platypus
Copy link

(Please fill out the issue template with your details)

Expected Behavior

TM manages to inject required resources

Actual Behavior

On websites using a strict Content-Security-Policy: require-trusted-types-for 'script'; / trusted-types, injection fails with the unhandled errors:

This document requires 'TrustedScript' assignment.
This document requires 'TrustedHTML' assignment.

(Full log attached)

Test the behavior here: https://benjamin-philipp.com/test-trusted-types.php?defaultPolicy=true

Specifications

  • Chromium: 93.0.4577.82 (Official Build) (64-bit)
  • TM: 4.13
  • OS: Windows 10

Script

(Please give an example of the script if applicable.)

// ==UserScript==
// @name		tmp
// @version		1.0.0
// @namespace	bp
// @match		https://benjamin-philipp.com/test-trusted-types.php*
// @require 	http://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js
// @require 	https://benjamin-philipp.com/js/gm/funcs.js?a=b
// @run-at		document-body
// @noframes
// @grant		none
// ==/UserScript==

console.log("With strict TrustedTypes implementation, this UserScript will fail while attempting to load the @requite scripts");
// $("#myElement").html("<p>toast</p>");

benjamin-philipp.com-1632523189216.log

@dev4min
Copy link

dev4min commented Sep 26, 2021

Same here!

@svArtist if you want a quick fix, this line of code fixed the problem for me:

window.trustedTypes.createPolicy('default', {createHTML: (string, sink) => string})

based on the down-voted answer in: https://stackoverflow.com/questions/61964265/getting-error-this-document-requires-trustedhtml-assignment-in-chrome

@Black-Platypus
Copy link
Author

@svArtist if you want a quick fix, this line of code fixed the problem for me:

window.trustedTypes.createPolicy('default', {createHTML: (string, sink) => string})

Hi!
That's certainly a good work-around for where it's applicable, but for people looking at this: there are some caveats

  • in the case of @requires breaking the script, any attempt to do this in the script itself would fail, since TM will already have broken down before it could execute the above. You would have to create a second script (without @requires, of course) for this, and make sure it gets executed first.
  • This requires that the CSP allows creation of a default policy
    • and that none has been set before

Let's hope the masterminds in the TM community can find robust ways of smoothing out the Trusted-Types experience.
It would be lovely if they could find a way to leverage browser APIs to circumvent the whole thing if need be. Power to the user! :)

@derjanb derjanb added the bug label Sep 26, 2021
@derjanb derjanb added this to the 4.14 milestone Sep 26, 2021
@Black-Platypus
Copy link
Author

Black-Platypus commented Sep 27, 2021

For anyone looking for a bandaid-fix in the meantime: I wrote a TT helper.
https://greasyfork.org/en/scripts/433051-trusted-types-helper

It does its best to enable reckless DOM modification again, and IF

  • you make sure to run it before your other scripts
  • the site allows setting a default policy, and
    • either our script gets executed before theirs,
    • or doesn't get overwritten,

Things should be like before the dreaded TT restrictions.

If we can't set a default policy, we're out of luck for this issue of dependencies breaking TM, but for general DOM manipulation from within scripts that do work, we can try to set a custom policy, it'll be assigned to the variable TTM.
Instead of using things like
someDomElement.innerHTML += "<div class='myClass'><p>some <b>content</b></p></div>";
use this approach

var e = document.createElement("div");
e.className = "myClass";
e.innerHTML = TTP.createHTML("<p>some <b>content</b></p>");
someDomElement.appendChild(e);

(Because it seems that Chrome stable at the moment doesn't even allow appending like someDomElement.innerHTML += actuallyTrustedHTML, which is a PITA)

@derjanb
Copy link
Member

derjanb commented Sep 27, 2021

Should be fixed at 4.14.6144 (in review|crx)

@7nik
Copy link

7nik commented Sep 27, 2021

doesn't even allow appending like someDomElement.innerHTML += actuallyTrustedHTML

I believe, it unfolds to

someDomElement.innerHTML = someDomElement.innerHTML + actuallyTrustedHTML;
// or, to be more detailed
someDomElement.innerHTML = someDomElement.innerHTML.concat(actuallyTrustedHTML.toString()); 
// that obviously returns a regular "untrusted" string

@Black-Platypus
Copy link
Author

I believe, it unfolds to

someDomElement.innerHTML = someDomElement.innerHTML + actuallyTrustedHTML;
// or, to be more detailed
someDomElement.innerHTML = someDomElement.innerHTML.concat(actuallyTrustedHTML.toString()); 
// that obviously returns a regular "untrusted" string

Oh, thank you for the insight.
Is that happening in a pre-compiler?
If it's the actual browser engine doing this, it should, IMO, refactor that to acknowledge appending trusted types to trusted contents. I'd hate having to manually create all properties/attributes of each outer element I'd like to add, which I'd have to create separately. Or writing a parser to do that for me o.o

@7nik
Copy link

7nik commented Sep 27, 2021

+= and other assignment shortenings are done in JS. You can check it in the docs: https://262.ecma-international.org/12.0/#sec-assignment-operators-runtime-semantics-evaluation

Also, you shouldn't use .innerHTML += mycode because it re-adds all existing HTML as well and it leads to removing all the listeners attached to the re-added elements and breaking all the links to these elements.
It's better to use insertAdjacentHTML:

someDomElement.insertAdjacentHTML("beforeend", mycode);

@Black-Platypus
Copy link
Author

Oh yes!! Thank you for reminding me!
I have been spoiled by jQuery and its .append for so long, being suddenly thrown back to vanilla JS and the common APIs, I feel a bit like a fish out of water and have to get back in touch with the basics 😅
Thank you so much for your helpful tips 👍

@jshwek
Copy link

jshwek commented Jun 23, 2024

To elaborate on @dev4min , the additions below allow you to do things like eval. As stated by @Black-Platypus , make sure it's the first // @require or it won't work.

(function(){ window.trustedTypes.createPolicy('default', { createHTML: (s, sink) => s, createScriptURL: (s, type, sink) => s, createScript: (s, type, sink) => s, emptyScript: (sink) => sink, }); })();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants