Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Securing Front Ends at Scale: Paving our way to...

Securing Front Ends at Scale: Paving our way to a post-XSS world

A talk given by Jen Ozmen and Aaron Shim at AppSec Village (DefCon 32).

Ecenaz (Jen) Ozmen

August 28, 2024
Tweet

More Decks by Ecenaz (Jen) Ozmen

Other Decks in Programming

Transcript

  1. Jen Ozmen Aaron Shim Aug 2024 Securing Front Ends at

    Scale: Paving our Way to a Post-XSS World
  2. • Software Engineer @ Google • Focusing on deploying security

    mitigations to Google’s web services Intro Jen
  3. • Software Engineer @ Google • Focus on Web Security

    adoption • Previously: Google Workspace, GCP Intros - Aaron
  4. Quick intro to Cross Site Scripting (XSS) Content Security Policy

    (CSP) and its different flavors Securing your apps against XSS at scale Perfect Types and the Post-XSS world Call to Action 01 02 03 04 05 Agenda
  5. XSS 35.6% Non-web issues 49.1% Mobile app vulnerabilities Business logic

    (authorization) Server/network misconfigurations ... Google Vulnerability Reward Program payouts
  6. • Risk: user input gets interpreted as 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
  7. • Allows the attacker to take control of the account

    of the logged in user– the attacker can do anything that the victim can What is XSS? • Client-side Remote code execution (RCE)
  8. DOM XSS is a client-side XSS variant 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;
  9. <!DOCTYPE html> <html> <head> <title>Page Title</title> <!-- Scripts loaded in

    the head. --> <script src="a.js"></script> <script src="b.js"></script> </head> <body> <h1>HTML Page</h1> <p>With some text</p> </body> </html> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Security-Policy" content="script-src 'strict-dynamic' 'sha256-NKwxejNe15ufvZg7F00NO4xNKmrnza4Z7HGPhGjt7/c=' https: 'unsafe-inline';object-src 'none';base-uri 'self';"> <title>Page Title</title> <!-- Generate preload tags for scripts that will be dynamically added. --> <link rel="preload" href="a.js" as="script" /> <link rel="preload" href="b.js" as="script" /> <!-- Try to keep script loading blocks near where they are. --> <script> var scripts = ['a.js','b.js']; scripts.forEach(function(scriptUrl) { var s = document.createElement('script'); s.src = scriptUrl; s.async = false; // preserve execution order. document.body.appendChild(s); }); </script> </head> <body> <h1>HTML Page</h1> <p>With some text</p> </body> </html>
  10. Element.innerHTML HTMLFormElement.action window.open HTMLAreaElement.href HTMLMediaElement.src HTMLFrameElement.src HTMLSourceElement.src HTMLTrackElement.src HTMLInputElement.src location.assign

    location.href document.write HTMLButtonElement.formAction HTMLFrameElement.srcdoc HTMLImageElement.src HTMLEmbededElement.src HTMLScriptElement.textContent HTMLInputElement.formAction HTMLScriptElement.innerText HTMLBaseElement.href
  11. The idea behind Trusted Types Require strings for passing (HTML,

    URL, script URL) values to DOM sinks. HTML string Script string Script URL string becomes
  12. The idea behind Trusted Types Require strings for passing (HTML,

    URL, script URL) values to DOM sinks. typed objects HTML string Script string Script URL string TrustedHTML TrustedScript TrustedScriptURL becomes
  13. if(self.trustedTypes && self.trustedTypes.createPolicy){ const myTrustedHTMLPolicy = trustedTypes.createPolicy('my-trusted-html-policy', { createHTML: (input)

    => { // Sanitize the input here if needed return DOMPurify.sanitize(input); } }); element.innerHTML = myTrustedHTMLPolicy.createHTML(value)); } else { element.innerHTML = value; } element.innerHTML = DOMPurify.sanitize(input, { RETURN_TRUSTED_TYPE: true });
  14. Use Frameworks Enforce Early Rely on the Right Tools Be

    Mindful of Third-Party Dependencies 01 02 03 04 Tactics
  15. // https://vitejs.dev/guide/api-plugin.html#configureserver const myPlugin = () => ({ name: 'configure-server',

    configureServer(server) { server.middlewares.use((req, res, next) => { res.setHeader('Content-Security-Policy', "require-trusted-types-for 'script'"); res.setHeader('Content-Security-Policy', "script-src ‘sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc=’"); next(); }) }, })
  16. const s = new StrictCsp(htmlString); // Refactor sourced scripts so

    that we can set a strict hash-based CSP s.refactorSourcedScriptsForHashBasedCsp(); // Hash inline scripts from this html file, if there are any const scriptHashes = s.hashAllInlineScripts(); // Generate a strict CSP as a string const strictCsp = StrictCsp.getStrictCsp(scriptHashes, { enableBrowserFallbacks: true, }); // Set this CSP via a meta tag s.addMetaTag(strictCsp); const htmlStringWithCsp = s.serializeDom(); Source: github.com/google/strict-csp/blob/main/strict-csp/README.md
  17. // https://vitejs.dev/guide/api-plugin.html#configureserver const myPlugin = () => ({ name: 'configure-server',

    configureServer(server) { server.middlewares.use((req, res, next) => { res.setHeader('Content-Security-Policy', "require-trusted-types-for 'script'"); res.setHeader('Content-Security-Policy', "script-src ‘sha256-RFWPLDbv2BY+rCkDzsE+0fr8ylGr2R2faWMhq4lfEQc=’"); next(); }) }, })
  18. // https://vitejs.dev/guide/api-plugin.html#configureserver const myPlugin = () => ({ name: 'configure-server',

    configureServer(server) { server.middlewares.use((req, res, next) => { let data = ''; res.on('data', (chunk) => { data += chunk; // Accumulate the response data }); res.on('end', () => { const s = new StrictCsp(data); // Refactor sourced scripts so that we can set a strict hash-based CSP s.refactorSourcedScriptsForHashBasedCsp(); // Hash inline scripts from this html file, if there are any const scriptHashes = s.hashAllInlineScripts(); // Generate a strict CSP as a string const strictCsp = StrictCsp.getStrictCsp(scriptHashes, { enableBrowserFallbacks: true, }); // Send the CSP as response headers res.setHeader('Content-Security-Policy', "require-trusted-types-for 'script'"); res.setHeader('Content-Security-Policy', strictCsp); // Send the modified data at once const htmlStringWithCsp = s.serializeDom(); res.end(htmlStringWithCsp); next(); }); }) }, }) Note: Specifically for Vite, this works better with https://vitejs.dev/guide/api-plugin#transformindexhtml but this example shows how the previous two slides can be combined in a framework-agnostic way
  19. [ { "filePath": "[...]/index.js", "messages": [ { "ruleId": "safety-web/trusted-types-checks", "message":

    "[ban-element-innerhtml-assignments] Assigning directly to Element#innerHTML can result in XSS vulnerabilities.", "line": 15, "column": 1, "messageId": "ban_element_innerhtml_assignments", "endLine": 15, "endColumn": 48 } ] } ] github.com/google/safety-web web.dev/articles/trusted-types#fix-violations element.innerHTML = value;
  20. element.innerHTML = value; import {sanitizeHtml} from 'safevalues'; import {safeElement} from

    'safevalues/dom'; ... const safeHtmlValue = sanitizeHtml(value); ... safeElement.setInnerHtml(element, safeHtmlValue); github.com/google/safevalues/blob/main/src/dom/xss-d om-remediation.md
  21. Secure by Default Frameworks Abstract away challenging security decisions away

    from the web developer Opinionated Wrapper APIs Guide developers towards safer coding patterns github.com/google/sa fevalues Static Analysis Check for potentially dangerous patterns and warn developers as early in the feedback loop as possible github.com/google/sa fety-web Runtime Enforcement Guarantee that insecure code will not run for the client web.dev/articles/strict -csp web.dev/articles/trust ed-types A Pipeline of Protections (devs) (users)
  22. Secure by Default Frameworks Abstract away challenging security decisions away

    from the web developer Opinionated Wrapper APIs Guide developers towards safer coding patterns github.com/google/sa fevalues Static Analysis Check for potentially dangerous patterns and warn developers as early in the feedback loop as possible Runtime Enforcement Guarantee that no insecure DOM APIs will run on the client A Pipeline of Protections (devs) (users)
  23. Secure by Default Frameworks Abstract away challenging security decisions away

    from the web developer New Web APIs? Is it possible to provide safe-by-default APIs as a part of the web platform? Static Analysis Check for potentially dangerous patterns and warn developers as early in the feedback loop as possible Runtime Enforcement Guarantee that no insecure DOM APIs will run on the client Trusted Types v2 / Perfect Types (devs) (users)