Types as DOM XSS protection Writing safe code from the start Rolling out Trusted Types for existing applications How to refactor Trusted Types blockers 01 02 03 04 05 Agenda
code What is XSS? <p>Description: foobar</p> <p>Description: <script>alert(1337)</script></p> <div onclick="code()"> data <script> code() </script> </div> • Malicious scripts are injected into otherwise benign and trusted websites
caused by many JavaScript APIs not being secure by default. • User controlled strings get converted into code • Many dangerous and error-prone DOM sinks like innerHTML Example: https://example.com/#<img src=x onerror=alert('xss')> How does XSS happen? var foo = location.hash.slice(1); document.querySelector('#foo').innerHTML = foo;
default ◦ User-controlled strings get turned into code ◦ ~60 APIs can do this • Client-side JavaScript is dynamic and complex ◦ Cannot statically analyze ◦ Sometimes inlined in HTML ◦ JS is getting complicated with complex client-side code • Organizational ◦ Dependencies! ◦ Complexity from too many engineers DOM XSS is a widespread problem
Tests catch Trusted Types violations too! • Prevent regressions ◦ New functionality that violates Trusted Types -> immediate breakage • Can be added as a static header in the server ◦ See Webpack documentation Enforce Trusted Types early! Content-Security-Policy: require-trusted-types-for 'script' <meta http-equiv="Content-Security-Policy" content="require-trusted-types-for ‘script’" />
with Trusted Types enforcement (~400+ applications) • Many of your favorite Google products– Gemini, Google Photos, Google Docs, Gmail etc. • Enforcement-by-default on new products (built on our modern web framework) Trusted Types Success Story at Google
Types compatible is difficult… • because we follow a comprehensive refactoring approach with our first-party applications • …but still worth it, especially because of the refactoring & runtime guarantees A word of warning…
{legacyUnsafeResourceUrl} from 'safevalues/restricted/legacy'; import {safeScriptEl} from 'safevalues/dom'; safeScriptEl.setSrc(script, legacyUnsafeResourceUrl(url));
draggable …) cause violations • Ideally: Patch upstream and upgrade our code: ◦ We submitted PRs on GitHub! ◦ Benefits: Help the community, clean integration with the product • However: ◦ PRs still pending the approval of the owners (discussion about TT and the change) ◦ Cannot upgrade certain libs easily ◦ Transitive dependency • Solution: ◦ Setup a private fork / vendoring (just like a monorepo!) ◦ Patch the violations ourselves and push them in our private fork Third Party Code
allows to fix violations without having to update a dependency we don’t have access to • Default policy: TT policy applied to ALL the inputs for a specific violation type What is a default policy? trustedTypes.createPolicy('default', { createHTML: (string) => { return DOMPurify.sanitize(string); } })
to the comprehensive approach • Not blocked by violations from external dependencies • Does not offer protection to non-compatible browsers • As vulnerable as the HTML sanitizer configurations • Need to configure the HTML sanitizer (lots of custom attributes in practice) • Could lead to silent behavioral changes not surfaced as violation reports Caveats of the Default Policy
in web security • Trusted Types provides a robust layer of defense against this threat • Trusted Types deployment is difficult … but worth it! ◦ 0 DOM XSS* in your application ◦ Path to enforcement increases security • Trusted Types deployment with many dependencies is definitely possible. • Please patch and upstream OSS libraries that you find! ◦ The ecosystem is stronger when we all work together Conclusions