-
Notifications
You must be signed in to change notification settings - Fork 27k
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
Add Trusted Types policy #13509
Add Trusted Types policy #13509
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs a review from @spanicker's team 👍
if (window?.trustedTypes?.createPolicy) { | ||
trustedTypesPolicy = window.trustedTypes.createPolicy('next-trusted-types', { | ||
// Needs security review regarding DOM XSS | ||
createHTML(dirty) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this even needed for this particular case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it isn't used, so the createHTML method here can be dropped.
I wonder if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please forgive the drive-by review by a rando. For context, I've worked on integrating Trusted Types into the lit-html project. Hopefully this advice is helpful :)
if (window?.trustedTypes?.createPolicy) { | ||
trustedTypesPolicy = window.trustedTypes.createPolicy('next-trusted-types', { | ||
// Needs security review regarding DOM XSS | ||
createHTML(dirty) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it isn't used, so the createHTML method here can be dropped.
createHTML(dirty) { | ||
return dirty.replace(/</g, '<') // Escapes `<` characters to prevent the creation of new HTML elements | ||
}, | ||
createScriptURL(dirty) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, the attack you're guarding against with createScriptUrl is an untrusted/malicious URL, which can execute arbitrary code (e.g. by loading a script from a hostile origin that exfiltrates user data, mines bitcoins, etc)
It looks like you construct the URLs in two places, at line 263 and line 103. If you are confident that the data used to construct those URLs can't come from untrusted sources, then you could have a createScriptURL function that just returns its argument, and call policy.createScriptUrl there (with comments about your assumptions).
Then, because policy isn't exported, you and your users can reduce the amount of code that needs to be subject to careful security review to just those where the policy is used in this file.
Hi, I am an intern at Google and last year I focused on trusted types (TT) integration to client side frameworks and I also created an integration for nextjs but I didn't create a PR as the code changes were needed in React and Webpack. In your PR you missed one execution in head-manager. The code will be executed if you include (Note: The PR's and examples and PR's I provide in next sections might be a bit outdated). Unfortunately (as you already know) for pleasant development with trusted types enabled you need to integrate with Webpack and React as well. There are open PRs for Webpack (webpack/webpack#9856 and webpack/webpack#9861) and React accepted TT behind feature flag (facebook/react#16157). Adding proper support for trusted types would require finishing the integration in these dependencies (merging webpack, removing the feature flag in React or using the build with TT). Using latest version of React (v16.13.1) without TT enabled, you are not able to use As nextjs can render the code on server side, it is possible to introduce reflected XSS (example). We also experimented with adding TT for React on server using the polyfill, however this is not in the threat model of TT. Last thing, if you want to use TT in dev mode as well, you can use CSP in report only mode. Unfortunately, that is the only way as you can't use TT default policy, because Webpack code is executed before user code. If you are interested in adding full trusted types support, we are glad to help you with integration or reviews. |
FWIW since next.js is now in Typescript, we can leverage tsec to statically discover Trusted Types violations. Where's what it shows now (there's at least one false positive violation with
React by now should support TT in |
Hi everyone :) I'd like to revisit this issue and make it possible to use Trusted Types in nextJS project - for both production and environment. I am working on it in my free time with no fixed schedule so I can't promise anything. So far I have a runnable nextJS project with Trusted Types enabled. So far, I've:
You can see the code in https://github.com/Siegrift/next.js/tree/tt-fixes and https://github.com/Siegrift/master-thesis/tree/master/code/tt-example-app |
👋 Someone from the Chrome team is going to start working on adding Trusted Types to Next.js early January. I'm going to close this PR as we can't land it as-is. I've opened a new issue for implementing trusted types here to track it: #32209 |
Resolves #13228, at least for production builds (doesn't fix the bug in the dev server, seemingly due to webpack), though a security review is needed.
Trusted Types is a new experimental DOM API created to combat DOM XSS, supported now in Chrome 83, with a polyfill available for other browsers. @tipra34 noticed that when requiring Trusted Types for scripts via
<meta httpEquiv="Content-Security-Policy" content="require-trusted-types-for 'script';" />
, it broke links (usingnext/link
) in Chrome 83: hovering over links would show the correct target URL, but clicking the link would do nothing. They ended up determining that the offending script src assignment took place inPageLoader.loadScript()
.This update adds a new custom Trusted Types policy by placing the following at the top of
page-loader.js
:...and changing the
script.src
assignment inloadScript()
toI'm not certain how secure
.replace(/</g, '<')
is as a security policy, so more experienced eyes there would be appreciated. Alternatively, we could use DOMPurify instead of creating a custom policy, and just...but that adds an extra dependency we aren't already using.
Also, this only fixes the bug for production builds (including when server-rendering). Using the dev server, the entire page breaks and the console points to a couple of different places where webpack is using
eval()
. Haven't done enough investigation yet to determine if that's something that we can fix on our end or that webpack needs to fix.