3 ms·
I’m a little skeptical. The example in the post, where you validate a URL against a regex before string-interpolating it into an HTML fragment, is essentially
by comex 7y ago
I’m a little skeptical. The example in the post, where you validate a URL against a regex before string-interpolating it into an HTML fragment, is essentially an anti-pattern. It’s too easy to screw up the regex and end up with an injection vector, especially in cases (probably the majority of them) where the thing being validated is less inherently constrained than “alphanumeric”. Instead, it’s best to use APIs that are safe by construction - in this case, using DOM APIs to create elements, without ever going through the intermediate string representation of HTML. See also, “Never sanitize your inputs!”:
http://blog.hackensplat.com/2013/09/never-sanitize-your-inputs.html?m=1 http://blog.hackensplat.com/2013/09/never-sanitize-your-inpu...
But if you use DOM APIs for everything, this “Trusted Types” API seems largely unnecessary. It would be enough to expose a switch to disable innerHTML and similar APIs entirely.
On the other hand, DOM APIs are rather unergonomic to use raw. Many wrappers exist, but React‘s JSX takes the cake by letting you write code that looks like string interpolation, yet compiles down to type-safe node creation. (Kind of like what parameterized queries do for SQL.) If we’re looking at browser-based approaches to solving XSS… how about standardizing something like JSX as a built-in browser feature? That way it could be used by everyone, even those who want to minimize dependencies or code directly for the browser.
(Yes, I know it’s been tried before, in the form of E4X. But that was a very different era…)
- rictic 7y agoTrusted Types are definitely designed with safe-by-construction APIs in mind. A primary use case is to write a safe-by-construction library that internally declares and uses a Trusted Types Policy that your CSP headers declare that they trust. If none of the policies in your CSP headers declare a createHTML method, then you can be confident that innerHTML can't be used anywhere in your app. You still want the other policy methods because there are other unsafe sinks in the DOM. For example: const scriptElem = document.createElement('script'); scriptElem.src = someUntrustedInput; document.body.appendChild(scriptElem); // arbitrary code execution! There's a number of these sinks, and they have legit important use cases, but you want to be able to sustainably review all such uses. For example, you could make a Trusted Types policy that will only accept a small number of constants for script urls. That way you can still create script elements to e.g. implement lazy loading of code, but you're certain that those APIs will not be used by an attacker to load unknown code.