-
Notifications
You must be signed in to change notification settings - Fork 73
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
Mechanism to constrain usages of unsafelyCreate #31
Comments
I agree; the actual security Trusted Types would bring is directly dependent on being able to constrain unsafe creations. To distill the possible ways of addressing that:
To facilitate locking down, we might want to expose an API to facilitate adding such app-specific, safe creation methods, with the function to lock down the setup completely (see e.g. koto/trusted-types@templatestrings-es6...koto:lockdown). This approach has the limitation of being runtime (so any code run before might be able to circumvent it), and, being in JavaScript, it doesn't propagate to new documents e.g. in iframes. The lesson to take from GWT, is that maybe we should look into disallowing unsafe creations by default (Speaking in CSP terms, allowing them would require an |
FYI, I extracted the granular enforcement of types proposal into #33. |
Re: propagating to iframes: I think it's OK to not propagate TrustedTypes enforcement to iframes: If the iframe is same-origin, its source is controlled by the same organization, and it's up to them to ensure that all their endpoints enable TrustedTypes. And if it's a different origin, it doesn't matter. Re: globally disallowing There are three broad categories of uses of
In a typical application, there should be only very few of (2) (say, a handful at most even in a fairly complex application), and none of (3) in newly developed code. Legacy code (gradually adopting the use of TrustedTypes) might have many of (3) however. |
https://www.npmjs.com/package/node-sec-patterns is one way project maintainers can constrain which NPM modules mint values that encapsulate security guarantees via a minter/verifier model where the verifier is ambiently available but access to the minter is checked. |
Regardless of the resulting API, there will be primitives available to user land code allowing to create trusted values (let's call them TT minters for analogy with https://github.com/mikesamuel/node-sec-patterns) i.e. values that would be allowed to be put into DOM even when TT enforcement is enabled. Those primitives will likely be references to functions - in the current iteration it's Either the platform features, or user land hardening code (which might be offered as a library) needs to guard the access to minters. Even if platform offers those, such methods need to be polyfillable, and should resist most known bypass methods - at least the ones that could not be detected at compile time. https://github.com/mikesamuel/node-sec-patterns offers a way of guarding function references by:
So, in the end, the minter references are avaliable globally (after a given module is loaded), but access to them is protected at runtime. While we can not fully adopt all the checks (there's no client side |
Yeah. Not having a reliable name for a compilation unit makes things difficult. If we did have a way to reliably determine a name for a compilation unit, we could bootstrap something by looking for a whitelist under That might make source-maps security-relevant though. |
I believe this is implemented with the policy parts of the new API. Please reopen if something's missing. |
When applying safe-value types in large scale software projects at Google, we've found it to be essential (see "Background" below) that there is a reasonably strong and automated mechanism to constrain wide-spread usage of unchecked conversions from string into a safe-value type (i.e., calls to
unsafelyCreate
).Requirements
It must be feasible for projects to surface reminders of coding and review guidelines to the project's developers if a commit / pull request introduces a new
unsafelyCreate
call site.It must be feasible for projects to centrally maintain an enforced whitelist of all call sites to
unsafelyCreate
(such that it is impossible to commit code that introduces non-whitelisted call sites). This allows the project's security expert to review all new usages for correctness, and to recommend alternatives to call-sites that aren't strictly necessary (and therefore undesirable, since they dilute the reviewability of the codebase)Third-party library concerns
Many libraries, such as jquery, expose APIs whose inputs flow down to DOM injection sinks (e.g., jquery's
html(...)
function flows down to.innerHTML
). I.e. these APIs effectively are injection sinks on their own.In the presence of TrustedTypes, these libraries should be refactored such that they themselves accept
TrustedHtml
etc and forward those values to the underlying DOM sink. However, if existing APIs perform any sort of transformations or construction of HTML markup on their own (this seems to be the case for jquery for instance), it's likely that the library's authors will resort tounsafelyCreate
.An application's developers and security reviewers then effectively have to trust the library's author to have used
unsafelyCreate
in a correct (and ideally, reviewable) way.A particular concern is that third-party library authors might simply wrap all uses of DOM sinks with
unsafelyCreate
in order to preserve existing functionality with minimal effort. Unfortunately, this will also preserve all vulnerabilities in the library, and the risk of vulnerabilities due to use of XSS sinks exposed by the library's API.Possible mechanisms to constrain usage
For JS source code that is subject to compilation a mechanism built into the compiler can be used, such as the Closure Compiler JS Conformance Framework.
In smaller projects a grep-based pre-commit hook might be sufficient; for this the only requirement is that unchecked conversion functions have reasonably unique names (to avoid false-positives).
unsafelyCreate
seems reasonable, but it might be helpful to include the produced type name in the function name, i.eunsafelyCreateTrustedResourceUrl
. Since these functions should be rarely used, an unwieldy name is not a concern and is in fact desirable.The above mechanisms will only constrain use of
unsafelyCreate
within the source of the application itself, but not in its third-party dependencies (unless they're checked into the same repository). In particular, they can't constrain use ofunsafelyCreate
in libraries that are script-src'd directly from a separate server.It might be desirable to have a browser-level mechanism to permit use of
unsafelyCreate
only in specific, whitelisted sources. Perhaps something along the lines of a CSP headertrusted-types-src 'nonce-xyz123'
, such thatunsafelyCreate
calls are only allowed from within scripts blessed by that nonce. This would allow an application developer/deployer to ensure thatunsafelyCreate
calls only occur in their own, security-reviewed code, and not in third-party libraries.Whitelisting based on CSP source is rather coarse-grained. Ideas for more fine-grained whitelisting:
unsafelyCreate
requires an additional nonce argument: The CSP header specifies a nonce,trusted-types-unsafely-create-nonce abc123
. Each call tounsafelyCreate
must be provided with the correct nonce,TrustedResourceURL.unsafelyCreate('abc123', 'https://static.example.com/my-lib.js')
. (of course this is only effective if the nonce cannot be directly obtained from JS). This makes callingunsafelyCreate
rather cumbersome (but again, that's desirable). In particular, source that callsunsafelyCreate
must be rewritten before serving to inject the nonce. This should also create an incentive for library authors to not callunsafelyCreate
, but rather refactor code to accept TrustedTypes in their API.Background
The key benefits of types-based approach to preventing injection vulnerabilities is two fold:
It replaces APIs that can potentially result in security vulnerabilities (i.e., injection sinks such as,
.href
or.innerHTML
assignment) with APIs that are inherently safe (for instance, Closure'sgoog.dom.safe.set{Location,Anchor}Href
andsetInnerHtml
, or, in this proposal the native href and innerHTML setters that only accept TrustedTypes). If an application only uses the DOM API via such mediated, inherently-safe APIs, application developers can no longer make mistakes in their use of the DOM API that result in XSS vulnerabilities.It makes it feasible for a security reviewer to arrive at a high-confidence assessment that an app is indeed free of (DOM) XSS vulnerabilities: She no longer has to audit every use of a DOM XSS sink throughout the app, and data flows therein; instead it's sufficient for her to audit only the code that constructs instances of the safe-value types (i.e., call sites of unsafelyCreate, and their fan-in).
IOW, the types-based approach replaces many XSS sinks (DOM APIs and properties) and typically many call sites throughout an application, with with fewer sinks (
unsafelyCreate
) with typically few call sites.To achieve its benefits both in terms of reducing actual XSS risk and facilitating efficient high-confidence security reviews, it is therefore crucial that call sites of unchecked conversions (i.e.,
unsafelyCreate
) are,rare, and ideally only occur in stable, security-reviewed library code, and
effectively reviewable (i.e. are not used in functions that in turn re-export an injection sink).
(corresponding guidelines on usage of unchecked conversions for SafeHtml types here, https://github.com/google/safe-html-types/blob/master/doc/safehtml-unchecked.md).
We've found that in practice, individual developers sometimes (often?) do not consider the impact on the above whole-system emerging properties (i.e., residual XSS risk and feasibility of high-confidence security assessments) of a use of an unchecked conversion they're introducing. We therefore found it necessary to introduce static checks that disallow uses of unchecked conversions without security review (in our case, we rely on the package visibility mechanism in the bazel build system, and in some cases compile-time checks implemented in error-prone).
Anecdote:
The concept of safe-value types was first introduced in Google Web Toolkit. The GWT
SafeHtml
type offers an unchecked conversionfromTrustedString
. Its documentation indicates that its use is strongly discouraged.Nevertheless, a few years after introduction of this API, we found O(1000) call-sites across GWT-based application source. Almost all of these were unnecessary (in the sense that they could have been rewritten using inherently-safe APIs such as
SafeHtmlTemplates
), and several of them did indeed introduce XSS vulnerabilities.The text was updated successfully, but these errors were encountered: