Champion(s): mikesamuel
Author(s): mikesamuel
Stage: Obsolete. Merged into dynamic-code-brand-checks
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:
- 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.
({})[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 to 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 portions of the inputs to %Function% and %eval% are TrustedScript.
eval(x)
treats x
as code.
new Function(x)
also treates x
as code.
The parameter list portion of a function can also be code since FormalParameterList elements may contain arbitrary default value expressions.
For example, the following function has a blank body, but still has a side effect.
(new Function('a = alert(1)', ''))()
Trusted Types defines a default policy which is invoked when a string reaches a sink to make it easier to migrate applications that pass around strings.
This policy is invoked when a string value reaches a sink, so any default policy's
createScript
callback is invoked on eval(myString)
.
If the callback throws an error, then eval
should be blocked.
But if the callback returns a value, result, then ToString(result) should be used as the source text to parse.
Being able to adjust the code that runs provides the maximum flexibility when dealing with a thorny legacy module that might otherwise prevent the entire application from running with XSS protections enabled.
To enable that, this proposal adjusts eval
and new Function
to expect return values from the host callout and
to use those in place of the inputs.
You can browse the ecmarkup output or browse the source.