Closed Rendez closed 5 years ago
The the main distinction is in that CSP is fundamentally an exploit mitigation: It does not remove the underlying bug from the code (e.g. injection of unsanitized untrusted data into HTML markup), but rather attempts to prevent its exploitation. Depending on the nature of the specific injection, there can still be security issues (see http://lcamtuf.coredump.cx/postxss/; this is probably more relevant wrt server-side injection, but fundamentally the point stands).
Aside from this fundamental issue, there are strong indications that it's fairly difficult to apply CSP correctly in practice, https://research.google.com/pubs/pub45542.
In addition, many web frameworks introduce "script gadgets" which permit a HTML injection vulnerability to turn into XSS even with CSP in place (see https://github.com/google/security-research-pocs/tree/master/script-gadgets).
Types on the other hand are a tool that helps developers build applications that are fundamentally free of underlying root-cause injection bugs to a high degree of confidence. Once you can ensure that only values of the appropriate types can reach a given injection sink, the bulk of the application code can no longer be the cause of injection bugs. In this setting, the only code that could potentially cause XSS is code involved in the construction of values of these types. The TrustedTypePolicy mechanism in turn allows application developers to structure code such that creation of types is tightly controlled and confined in small, typically stable, parts of the overall code base.
This article describes the types-based approach to prevention of injection bugs in more detail: https://research.google.com/pubs/pub42934. It's been very successfully applied at Google in our largest web applications. Here, the implementation relies on static checks to ensure that only properly-typed values reach injection sinks. TrustedTypes brings this approach natively to the web platform, and ensures the same invariant dynamically, which allows the approach to be used in JS code that doesn't have static type annotations.
That said, CSP is nevertheless a valuable complementary mitigation. Given a web framework that helps with setting up and maintaining policies, it's very little effort to deploy, and there's really no reason not to use it in addition to TrustedTypes.
Thanks for the question - it's very valuable to get the external feedback (and thanks for trying out the implementation, please raise additional issues or mail me directly if you run into problems, we're eager to help).
To extend what @xtofian said with some practical notes. What we find is that the CSP policies are useful when you're trying to limit what script executes on the page (based on its URL on nonce/hash), but in practice the applications nowadays are complex enough that it's extremely difficult to ensure that the code that runs doesn't contain a client-side injection vulnerability (e.g. in the form of script gadgets, which we found in most of the JS frameworks). The most you could get from an "ideal" CSP at that point is a block when that injection flaw is being exploited to run additional scripts (in practice, we found that even this could be bypassed for a lot of combinations of CSP flavors and frameworks) - but it gets tricky once non-script vectors are used (like postxss @xtofian mentioned).
Trusted Types offers a different approach - regardless of which scripts execute in your application, it tries to isolate their security-sensitive capabilities in small code fragments that are easy to review & control. In a way that's a more invasive (because it requires one to rewrite the code), but more precise security control than CSP, but it also is complementary to CSP, which works more at the request-response level.
Additional unique property of Trusted Types is that you can benefit from them even if the browser does not support it . As they require you to rewrite the DOM-touching parts of the application to be TT-compliant (and create policies for them), after running e.g. the integration tests, or monitoring the violations for some time, you can be sure that there is no code path in your application that uses "raw" DOM sinks. If that's the case, in non-supporting browsers you just have to add this tinyfill:
TrustedTypes={createPolicy:(n, rules) => rules}
and be sure that all the security-sensitive values reaching DOM have passed a policy (caveat: this assumes there's no default policy in your application). You have removed a vulnerability class from your application. With CSP you can only mitigate the exploits for vulnerabilities that still exist in your code, ready to be exploited if new bypass technique comes around.
Thank you both for the amazing explanation and resources. In the scope of this answer's discoverability, it would in my opinion, really help making them more visible: such as in the readme file, or something like that. For this proposal to gather user support, helps if it's understood for users who aren't so knowledgeable yet on less studied exploiting techniques.
Totally, we'll create a FAQ very soon.
Hi there, I've been browsing through the spec and source code (and implementing a policy on a local project) for an entire day. The proposal is very interesting, but there are a couple of things that aren't clear to me:
Let's say. based on the list of policies for script-src, I could protect my domain against execution of any kind of script in my DOM by providing a 'nonce-' for my domain inside my CSP header. Same goes for origins of images, iframes, etc. etc.
I'm struggling to understand if TrustedTypes are an alternative to CSP, or complementary approach.
Could you please clarify it for me?
Many thanks in advance.