ecma262 icon indicating copy to clipboard operation
ecma262 copied to clipboard

Provide HostEnsureCanCompileString implementors more context

Open mikesamuel opened this issue 6 years ago • 14 comments

Originally floated as a strawman

eval is Evil

The eval function is the most misused feature of JavaScript. Avoid it.

-- Douglas Crockford, "JavaScript: The Good Parts"

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')() to get a handle to the global object then eval has to work.

This prevents the use of security measures like:

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.

({})[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 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.

Fixes #938.

mikesamuel avatar Apr 03 '19 16:04 mikesamuel

I'd like to schedule this for a needs_consensus slot per https://github.com/tc39/proposals/pull/209#discussion_r271809863

This should be a semantics free change from the ES side.

Tracking issue filed on the HTML5 side: https://github.com/whatwg/html/issues/4501

mikesamuel avatar Apr 03 '19 16:04 mikesamuel

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. https://github.com/tc39/test262/issues/2120

Would it be sufficient to include a prose section on what to test like the below?

Run in the context of a HostEnsureCanCompileStrings callout that does blah blah blah:

// test code here

like https://gist.github.com/mikesamuel/5c71584fc10a603167111e933cdc650d

mikesamuel avatar Apr 03 '19 19:04 mikesamuel

Fixes #938

mikesamuel avatar Apr 03 '19 19:04 mikesamuel

It may indeed not be possible to test; that's something i think the test262 maintainers can help confirm.

ljharb avatar Apr 03 '19 19:04 ljharb

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 https://github.com/tc39/ecma262/issues/1495 Edit 2: Actually, it doesn't.

littledan avatar Apr 07 '19 12:04 littledan

@littledan, I put together https://github.com/mikesamuel/evalable#tc39-proposal-evalable-stage-0 based on https://github.com/tc39/ecma262/issues/938#issuecomment-457352474

mikesamuel avatar Apr 07 '19 13:04 mikesamuel

Question. Do we even need to callout to HostEnsureCanCompileStrings for the case of new Function() (with no params)? It doesn't seem to me that new Function() on it's own can be used as a vector for XSS attacks.

Jamesernator avatar Apr 18 '19 16:04 Jamesernator

@Jamesernator You're right that (new Function) is not an XSS risk but I suspect I'm missing something more in your question.

IIUC new Function reaches CreateDynamicFunction with zero arguments which reaches 19.2.1.1.1.1 step 13

  1. If argCount = 0, let bodyText be the empty String.

so new Function('') and (new Function) are equivalent and both are already guarded by the host callout.

mikesamuel avatar Apr 18 '19 16:04 mikesamuel

It just seems surprising to me that new Function() needs to invoke the machinery for checking whether or not a string is safe given that it wasn't given a string in the first place. (Given that eval(nonString) doesn't bother invoking the HostEnsureCanCompileStrings machinery when it's not given a string).

Jamesernator avatar Apr 30 '19 06:04 Jamesernator

We would try to revamp this PR (cc @ptomato)

caridy avatar Nov 02 '23 18:11 caridy

I've opened a rebased version of this over at https://github.com/tc39/ecma262/pull/3222.

ptomato avatar Nov 16 '23 01:11 ptomato

@ptomato should we close this, or do you prefer to keep it around for when the time comes to work on trusted types?

caridy avatar Nov 29 '23 03:11 caridy

If it should be closed, it’d be done on merging of the replacement, I’d expect.

ljharb avatar Nov 29 '23 04:11 ljharb

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).

nicolo-ribaudo avatar Nov 29 '23 11:11 nicolo-ribaudo