-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
Provide HostEnsureCanCompileString implementors more context #1498
base: main
Are you sure you want to change the base?
Provide HostEnsureCanCompileString implementors more context #1498
Conversation
Originally floated as a [strawman][1] > ### `eval` is Evil > > The `eval` function is the most misused feature of JavaScript. Avoid it. > > -- <cite>Douglas Crockford, "JavaScript: The Good Parts"</cite> `eval` and its friend `new Function` are problematic because, too often, an attacker can turn it against the application. Most code avoids `eval`, but JS programs are no longer small, and self-contained as they were when Crock wrote that. If one module uses `eval`, even if it's as simple as [`Function('return this')()`][2] to get a handle to the global object then `eval` has to work. This prevents the use of security measures like: * [Content-Security-Policy][] * `node --disallow_code_generation_from_strings` which turn off `eval` globally. As JavaScript programs get larger, the chance that no part of it needs `eval` or `Function()` to operate gets smaller. ---- It is difficult in JavaScript for a code reviewer to determine that code never uses these operators. For example, the below can when `x` is constructor. ```js ({})[x][x](y)() // ({})[x] === Object // ({})[x][x] === Function // ({})[x][x](y) ~ Function(y) ``` So code review and developer training are unlikely to prevent abuse of these operators. ---- This aims to solve the problem by providing more context to host environments so that they can make finer-grained trust decisions. The [Trusted Types proposal][3] aims to allow JavaScript development to scale securely. It makes it easy to separate: * the decisions to trust a chunk of code to load. * the check that an input to a sensitive operator like `eval` is trustworthy. This allows trust decisions tto be made where the maximum context is available and allows these decisions to be concentrated in small amounts of thoroughly reviewed code The checks can also be moved into host code so that they reliably happen before irrevocable actions like code loading complete. Specifically, Trusted Types would like to require that the code portion of the inputs to %Function% and %eval% are [*TrustedScript*][4]. [1]: https://github.com/mikesamuel/proposal-hostensurecancompilestrings-passthru/ [2]: https://github.com/zloirock/core-js/blob/2a005abe68520248d4431cab70d86e40b55d6e98/packages/core-js/internals/global.js#L5 [3]: https://wicg.github.io/trusted-types/dist/spec/ [4]: https://wicg.github.io/trusted-types/dist/spec/#typedef-trustedscript [Content-Security-Policy]: https://csp.withgoogle.com/docs/index.html
I'd like to schedule this for a needs_consensus slot per tc39/proposals#209 (comment) This should be a semantics free change from the ES side. Tracking issue filed on the HTML5 side: whatwg/html#4501 |
1. If _argCount_ = 0, let _bodyText_ be the empty String. | ||
1. Else if _argCount_ = 1, let _bodyText_ be _args_[0]. | ||
1. Else _argCount_ ≥ 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The goal of splitting the loop out of this if-tree is to preserve the order of side effects due to stringification while allowing the host callout access to bodyText.
The order of events should stay the same:
- Host callout
- Parameter name arguments stringified in order
- Body text stringified
How might one specify tests? AFAIK, there's no way for a test262 implementation to specify that a test runs in the context of a less-than-completely permissive host callout. tc39/test262#2120 Would it be sufficient to include a prose section on what to test like the below?
like https://gist.github.com/mikesamuel/5c71584fc10a603167111e933cdc650d |
Fixes #938 |
It may indeed not be possible to test; that's something i think the test262 maintainers can help confirm. |
I think you'd need more changes than just this. Step 2 of PerformEval will not evaluate non-String arguments, so it wouldn't really be very useful to apply with a TrustedScript. Edit: I see, this is covered by #1495 |
@littledan, I put together https://github.com/mikesamuel/evalable#tc39-proposal-evalable-stage-0 based on #938 (comment) |
Question. Do we even need to callout to |
@Jamesernator IIUC
so |
It just seems surprising to me that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This layering change generally LGTM. I'd like to wait to land it until we have a PR within a host environment that takes advantage of this PR.
1. Let _bodyText_ be _args_[_argCount_ - 1]. | ||
1. Perform ? HostEnsureCanCompileStrings(_callerRealm_, _calleeRealm_, _goal_, _bodyText_). | ||
1. Let _P_ be the empty String. | ||
1. If _argCount_ = 1, let _bodyText_ be _args_[0]. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand the purpose of this line. Wasn't this already handled four lines up?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It indeed was.
Instead of splitting discussion of a related topic into 10 min for [an editorial change](tc39/ecma262#1498) and 15 min for what [WICG/trusted-types](https://mikesamuel.github.io/proposal-hostensurecancompilestrings-passthru/) needs, consolidate them into one discussion of the latter. Apologies if the diff is ugly. I just removed one row from one table and added its time to a row in another table.
1. If _argCount_ = 0, let _bodyText_ be the empty String. | ||
1. Else if _argCount_ = 1, let _bodyText_ be _args_[0]. | ||
1. Else _argCount_ ≥ 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. Else _argCount_ ≥ 1, | |
1. Else, | |
1. Assert: _argCount_ ≥ 1, |
1. If _argCount_ = 1, let _bodyText_ be _args_[0]. | ||
1. Else _argCount_ > 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1. If _argCount_ = 1, let _bodyText_ be _args_[0]. | |
1. Else _argCount_ > 1, | |
1. If _argCount_ > 1, |
3d0c24c
to
7a79833
Compare
We would try to revamp this PR (cc @ptomato) |
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks
I've opened a rebased version of this over at #3222. |
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks Co-authored-by: Philip Chimento <pchimento@igalia.com>
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks Co-authored-by: Philip Chimento <pchimento@igalia.com>
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks Co-authored-by: Philip Chimento <pchimento@igalia.com>
This is a continuation of Mike Samuel's work in tc39#1498. Due to tc39#2670, this change can be made simpler than it previously was. This change provides the source text to be evaluated, and the grammar symbol that should be used to parse it, to the host hook HostEnsureCanCompileStrings. One example of where this is needed is for allowing a Content Security Policy to provide hashes for code executed via `eval()` or `new Function()`: w3c/webappsec-csp#623 This is useful on its own, but has come up again in the topic of ShadowRealm-HTML integration. In a ShadowRealm you can either execute code asynchronously, with ShadowRealm.p.importValue, or synchronously, with ShadowRealm.p.evaluate. Because the latter uses `eval()` inside the ShadowRealm, it's subject to CSP rules, so the only CSP policy that will let you execute synchronously in the realm is `unsafe-eval`. The original purpose of tc39#1498 was to support Trusted Types, which is still a goal of this PR. This is a separate needs-consensus PR, rather than being part of the ShadowRealm proposal, because it's useful independently of ShadowRealm, and also ShadowRealm would go forward regardless of whether this goes forward. Prior art: https://github.com/tc39/proposal-dynamic-code-brand-checks Co-authored-by: Philip Chimento <pchimento@igalia.com>
@ptomato should we close this, or do you prefer to keep it around for when the time comes to work on trusted types? |
If it should be closed, it’d be done on merging of the replacement, I’d expect. |
Note that the other PR only replaces part of the motivation of this one. If we'll want to ever support trusted types, we'll need to also pass the uncoerced objects to the host (which is what this PR does). |
Originally floated as a strawman
eval
and its friendnew Function
are problematic because, toooften, an attacker can turn it against the application.
Most code avoids
eval
, but JS programs are no longer small, andself-contained as they were when Crock wrote that.
If one module uses
eval
, even if it's as simple asFunction('return this')()
to get a handle to theglobal object then
eval
has to work.This prevents the use of security measures like:
node --disallow_code_generation_from_strings
which turn off
eval
globally.As JavaScript programs get larger, the chance that no part of it needs
eval
orFunction()
to operate gets smaller.
It is difficult in JavaScript for a code reviewer to determine that
code never uses these operators. For example, the below can when
x
is constructor.So code review and developer training are unlikely to prevent abuse of these
operators.
This aims to solve the problem by providing more context to host environments so that they
can make finer-grained trust decisions.
The Trusted Types proposal aims to allow JavaScript development to scale securely.
It makes it easy to separate:
eval
is trustworthy.This allows trust decisions tto be made where the maximum context is
available and allows these decisions to be concentrated in small
amounts of thoroughly reviewed code
The checks can also be moved into host code so that they reliably happen before
irrevocable actions like code loading complete.
Specifically, Trusted Types would like to require that the code portion of the
inputs to %Function% and %eval% are TrustedScript.
Fixes #938.