Truly safe `eval` using ES6 `Proxy` and `with`? - javascript

It's a well known fact that neither Javascript's eval keyword nor Function objects created from strings should ever for any reason be used to run untrusted code.
However, I'm wondering if ES6 proxies change that. Consider:
let env = {eval: eval};
let proxy = new Proxy(env, { has: () => true });
with(proxy) {eval('...')}
The proxy object pretends to have all possible properties, which means that it blocks the search of higher scopes. Within the with block, any properties not set on env appear undefined, and any global properties set inside the with block are actually set on env.
This seems to allow me to set up a completely controlled and isolated environment for the evaled code to run in. What are the risks?
Here are a few concerns I can see:
Don't put anything that references window, or document, or localStorage, or anything else sensitive, into env.
Don't put any mutable object into env unless you're ok with untrusted code mutating it.
Solution: make deep copies if necessary.
Code inside the with block has no access to anything outside it. If it needs things like Math, Object, or String, they have to be put in env - which means these can be modified by malicious code. Even the eval function in my minimal example above can be modified.
Solution: Create proxies for these objects to white-list read-only access to specific properties.
As long as you follow these guidelines, is this actually safe? Are there other concerns?

It is quite easy to break out of this environment, via a number of different ways, some or all of which might possibly be mitigated:
Object, Array, and RegExp literals ({ }, [ ], and /.../) are unimpeded by the Proxy and allow access to (and mutation of) Object.protoype, Array.prototype, and RegExp.prototype. You can, however, lock these with Object.freeze before running your eval.
You must delete env.eval within your evaled string, or else the script can execute global code by renaming the eval function like globalEval = eval;
You cannot prevent the creation of new functions, which may use a global this object: (function () { this.globalFunc(); })(). Possibly enforcing strict mode by appending "use strict"; to your evaled input could eliminate this escape vector.
Any access to the Function constructor (via (a=>a).__proto__.constructor) allows execution of global code. You can delete Function.constructor to prevent this, but there may be other ways to access Function.

Related

Why eval can't be used as a variable under strict mode [duplicate]

According to the spec (Annex C), strict-mode code can't do pretty much anything that might assign any identifier with the name eval. I can understand that one might want to restrict use of the actual eval function, but I don't see what purpose is served by restricting use of the name?
bobince is basically correct. (I work on SpiderMonkey, Mozilla's JS engine, have implemented various parts of ES5 in it, and follow ECMAScript discussions as time permits.) You (implementers and readers both) really do want eval to be the canonical eval, and you want arguments to be the canonical arguments. Using strict mode you can mostly get this.
But I will point out that ES5's restrictions here are not as much as would be desirable. First, and to correct bobince slightly, even with strict mode you can't be sure eval is the original eval function:
"use strict";
this.eval = function() { return "ohai"; };
eval("7 + 10"); // "ohai"
This is the well-known (among JS aficionados) global object mistake: that scripts use a global object, shared across scripts, nameable and modifiable, to resolve names. If you couldn't refer to the object where global variables are bound, you wouldn't have this problem. It's likely ES6 will fix this through another opt-in system (possibly out-of-band like a MIME type, but that's unclear yet) always scoped to entire scripts.
But even without the nameable, mutable global object, you still have problems because strict mode can be scoped to functions:
function outer()
{
var eval = function() { return "kthxbai"; };
function inner()
{
"use strict";
return eval("2 + 5");
}
return inner();
}
outer(); // "kthxbai"
These problems exist even in the presence of strict mode, and they won't go away until ES6 at the earliest, as it will probably remove the global object and unconditionally enforce strict mode restrictions.
So eval in strict mode is still a little weird in that it can refer to not-eval. But handling that is no big deal -- at runtime the implementation can check for the real eval and if that fails just do what it'd do if the syntax happened to use a name other than eval. This requires that an expression like eval(...) be handled specially. But any good implementation did that anyway, because of eval's non-statically-observable behavior (mutating local variables and arguments, introducing new variables [now de-fanged in strict mode -- variable declarations in strict mode eval code are local to the eval code], and so on), so it's no real burden.
It's worth noting none of this applies to arguments as a fake special form. Either you have strict mode by way of a function scope, in which case you'd see that function's arguments rather than arguments assigned in an outer scope, or you have it by way of a global scope, in which case arguments has no special behavior. (Why forbid mutation of arguments in global strict mode code? Probably simplicity, plus forcing developers to treat them as more of a special form everywhere, but I'm not certain.)
I can only speculate, but it seems to me that ES5-strict is saying that eval and arguments should be considered as raw syntax, not identifiers. It is reasonable that these two features should be implemented at the syntactical level, because they have Amazing Funky Magic behaviours that cannot be reproduced by a normal function.
(In particular eval may write to local variables in the function that calls it, and writing to arguments bizarrely changes the values of local variables corresponding to the arguments. Though this behaviour seems to be going away in strict mode, thankfully.)
For compatibility reasons, ES5 can't actually make eval and arguments syntactical. So they do the nearest they can, which is to say that the identifier arguments always refers to arguments magic and the identifier eval always exclusively refers to eval magic.
It could also improve the possibilities for optimisation, if JS engines can be sure whether a function contains magic.

Why do we prepend global variables with `window.`?

In a lot of code examples I see around the internet, global variables such as innerWidth, onresize, navigator, etc., are written as window.innerWidth, window.onresize, window.navigator, respectively.
Why are some of these globals prepended with window. and others, such as document and console typically not prepended?
Edit:
I know how OOP works and that I am accessing various properties of the window object. I'm no novice to JavaScript. I'm sorry if my question may have been unclear. I have been programming in JS for years but have never questioned this convention, hence my question.
In essence, I am asking why we don't put window. before document, but we put it before innerWidth. Is it simply a matter of clarity? In theory, shouldn't I be able to reference any of the globals without the window. prefix and have no problem?
It's unfortunate but window in your browser refers to one object which represents two logically distinct concepts :
an instance of Window, an object with well defined properties like Window.innerWidth, logically mapped to your browser's window (or rather the tab, today, but that distinction is hidden from your script)
the global object to whom all global variables are attached as properties
Semantically, it's cleaner to not prefix the global variables, unrelated with the Window concept, with window..
Now note that this introduces a problem when you refer to your global specific variable like myThing : it's hard to know if you're knowingly referring to a global variable or if it's declared in some intermediate scope (or if you just forgot to declare the variable with var). which leads to a situation in which you won't use window. only for properties of the instance of Window but also for your specific global variables. Of course in practice you'll avoid global variables as much as possible.
Not prefixing with window. also has the advantage, when you forget a var declaration or a library import, to make your code fail fast in a not subtle way (which is better than failing in production in a hard to debug way) :
window.undeclaredVariable // no error, just an undefined value
undeclaredVariable // reference error
JavaScript would probably have been better with a distinction between those two concepts (something like global or root as in node).
All the global functions and variables are attached to the object activator, this object dependent of your host environment (browser, node, etc), in the browser environment the object activator is the window object, so each global function could be access with window.console, this.console or just console, I think the prepend is useful to have a more readable code.
You could access to global scoped variables without the window prepend just innerWidth.
Think of it like objects. You are trying to get the innerWidth of the window object its self. Document is the same way. You are trying to get those variables that describe the document itself instead of the window as a whole. And console is just that, a console that you console.log to for debugging. It also has its own properties.
They may be global variables, but they still belong to and describe a specific "object" that you must call on first. If that makes sense.

How can I run a string as if it where javascript code?

How can I run a string
as if it where javascript code?
//The user inputs javascript code and clicks run and it runs the javascript code
function getCode () {
retrun code();
}
funciton runCode() {
run(getCode());
}
The function you want is eval.
function funCode() {
eval(getCode());
};
While eval() certainly works, another option is to take the code, and pass it to the Function constructor. This creates a new function with your code as the function body.
Doing this has some benefits.
it's variable scope will be the global scope, so the code you run won't interfere with any local variables
it has much better performance
you can force the code into strict mode, and can shadow the window and self identifiers, making it difficult to create global variables
funciton runCode() {
// create `window` param---v v--- and `self` param
var f = new Function("window", "self", " 'use strict'; " + getCode())
// force strict mode -----------^
var self = {}
f.call(self, self, self); // pass an object to the `window` and `self` param
// and set the same object as the `this` value
}
This certainly doesn't provide full security, but can provide a little more of a "sandbox" for the code to run in.
You can also examine the self object after the call to see if it tried to create any globals.
It may also be useful to wrap the code or the function execution in a try/catch, and then examine any errors that were thrown.
eval() is the function you're looking for.
But use it wisely or not at all as it's fraught with security risks.
var exec_string = 'alert(\'Hello, World!\')';
eval(exec_string);
Outputs "Hello, World!" in an alert
You can use the built-in eval function:
function runCode() {
eval(getCode());
}
Note that this function is a bit "magical"; the interpreter gives it information from the surrounding lexical context. As a result, it has to be called as eval; you can't set run = eval and then call run. (You could, however, write function run(s) { return eval(s); }.)
As other posters have indicated, eval is the method that exists for this purpose. However, eval will execute any javascript code regardless of whether it is harmful or not (e.g. javascript from a third party source might have an infinite loop or, worse, malicious behaviour). There is the common refrain
eval == evil
and as such eval is generally regarded as an anti-pattern. However, taking such a simplistic approach is wrong. Instead, it is perfectly acceptable to use eval in cases where the string you wish to evaluate can be trusted. However it turns out there are relatively few cases where this is true. Obviously anything from a third party site is dangerous (even if you trust the owners, they may have been hacked). Even from your own server you may be susceptible to "man in the middle" attacks although this is fairly unlikely for most sites.
The most common reason to need to evaluate javascript strings is rendering third party web pages. In this case it is generally preferable to render the page on the server (e.g. http://phantomjs.org/) and then transmit the result to the browser. That way the browser is protected from running unsafe code.
Another, increasingly common, use case is interactive tutorial websites where the user gets to see the result of the code they have typed in. In this case you are less worried about malicious scripts as the only ones the user will suffer from are those that he/she has typed themselves. But in this case you are still worried about mistakes that will break the functionality of your site (e.g. infinite loops) and so it is still recommended to carry out the evaluation on your server (with appropriate safeguards) so that the inputed javascript cannot break anything.
A possible alternative to eval is Google's caja (https://code.google.com/p/google-caja/) which intends to solve all these problems, however I've never used it myself and can't comment on its usefulness.

Why do you need to pass in arguments to a self executing function in javascript if the variable is global?

I was looking at the code for the underscore.js library (jQuery does the same thing) and just wanted some clarification on why the window object is getting passed into the self executing function.
For example:
(function() { //Line 6
var root = this; //Line 12
//Bunch of code
}).call(this); //Very Bottom
Since this is global, why is it being passed into the function? Wouldn't the following work as well? What issues would arrise doing it this way?
(function() {
var root = this;
//Bunch of code
}).call();
I suspect the reason is ECMAScript 5 strict mode.
In non-strict mode, this IIFE
(function() {
console.log(this); // window or global
})();
logs the window object (or the global object, if you're on a node.js server), because the global object is supplied as this to functions that don't run as a method of an object.
Compare that result to
"use strict";
(function() {
console.log(this); // undefined
})();
In strict mode, the this of a bare-invoked function is undefined. Therefore, the Underscore authors use call to supply an explicit this to the anonymous function so that it is standardized across strict and non-strict mode. Simply invoking the function (as I did in my examples) or using .call() leads to an inconsistency that can be solved with .call(this).
jQuery does the same thing, and you can find several answers to your question on SO by searching along those lines.
There are two reasons to have an always-available global variable like window in local scope, both of which are for the sake of fairly minor optimizations:
Loading time. Looking up a local variable takes a tiny bit less time than looking up a global variable, because the interpreter doesn't have to look as far up the context tree. Over the length of a function the size of Underscore or jQuery, that can theoretically add up to a less-trivial amount of time on slower machines.
Filesize. Javascript minification relies on the fact that variables can be named anything as long as they're consistent. myLongVariableName becomes a in the minified version. The catch, of course, is that this can only apply to variables defined inside the script; anything it's pulling from outside has to keep the same name to work, because if you shrink window down to pr the interpreter won't know what the hell you're talking about. By shadowing it with a reference to itself, Minify can do things like:
(function(A){ B(A, {...}); A.doStuff(); //etc });})(window)
and every time you would otherwise have put window (6 characters) you now have A (1 character). Again, not major, but in a large file that needs to explicitly call window on a regular basis for scope management it can be important, and you've already got an advantage by a few characters if you use it twice. And in large, popular libraries that get served by limited servers and to people who might have lousy Internet plans, every byte counts.
Edit after reading comments on question:
If you look at what function.call() actually does, your second snippet wouldn't actually work - the this being passed in isn't an argument, it's an explicit calling context for the function, and you have to provide it to .call(). The line at the beginning of the file serves the two purposes above. The reason for setting the context explicitly with call is futureproofing - right now, anonymous functions get the global context, but theoretically that could change, be discouraged in a future ECMA specification, or behave oddly on a niche browser. For something that half the Internet uses, it's best to be more explicit and avoid the issue entirely. The this/window choice at the top level I think must have something to do with worrying about non-PC devices (i.e. mobile) potentially using a different name for their top-level object.

Why does EcmaScript 5 strict mode go to such great lengths to restrict the identifier `eval`

According to the spec (Annex C), strict-mode code can't do pretty much anything that might assign any identifier with the name eval. I can understand that one might want to restrict use of the actual eval function, but I don't see what purpose is served by restricting use of the name?
bobince is basically correct. (I work on SpiderMonkey, Mozilla's JS engine, have implemented various parts of ES5 in it, and follow ECMAScript discussions as time permits.) You (implementers and readers both) really do want eval to be the canonical eval, and you want arguments to be the canonical arguments. Using strict mode you can mostly get this.
But I will point out that ES5's restrictions here are not as much as would be desirable. First, and to correct bobince slightly, even with strict mode you can't be sure eval is the original eval function:
"use strict";
this.eval = function() { return "ohai"; };
eval("7 + 10"); // "ohai"
This is the well-known (among JS aficionados) global object mistake: that scripts use a global object, shared across scripts, nameable and modifiable, to resolve names. If you couldn't refer to the object where global variables are bound, you wouldn't have this problem. It's likely ES6 will fix this through another opt-in system (possibly out-of-band like a MIME type, but that's unclear yet) always scoped to entire scripts.
But even without the nameable, mutable global object, you still have problems because strict mode can be scoped to functions:
function outer()
{
var eval = function() { return "kthxbai"; };
function inner()
{
"use strict";
return eval("2 + 5");
}
return inner();
}
outer(); // "kthxbai"
These problems exist even in the presence of strict mode, and they won't go away until ES6 at the earliest, as it will probably remove the global object and unconditionally enforce strict mode restrictions.
So eval in strict mode is still a little weird in that it can refer to not-eval. But handling that is no big deal -- at runtime the implementation can check for the real eval and if that fails just do what it'd do if the syntax happened to use a name other than eval. This requires that an expression like eval(...) be handled specially. But any good implementation did that anyway, because of eval's non-statically-observable behavior (mutating local variables and arguments, introducing new variables [now de-fanged in strict mode -- variable declarations in strict mode eval code are local to the eval code], and so on), so it's no real burden.
It's worth noting none of this applies to arguments as a fake special form. Either you have strict mode by way of a function scope, in which case you'd see that function's arguments rather than arguments assigned in an outer scope, or you have it by way of a global scope, in which case arguments has no special behavior. (Why forbid mutation of arguments in global strict mode code? Probably simplicity, plus forcing developers to treat them as more of a special form everywhere, but I'm not certain.)
I can only speculate, but it seems to me that ES5-strict is saying that eval and arguments should be considered as raw syntax, not identifiers. It is reasonable that these two features should be implemented at the syntactical level, because they have Amazing Funky Magic behaviours that cannot be reproduced by a normal function.
(In particular eval may write to local variables in the function that calls it, and writing to arguments bizarrely changes the values of local variables corresponding to the arguments. Though this behaviour seems to be going away in strict mode, thankfully.)
For compatibility reasons, ES5 can't actually make eval and arguments syntactical. So they do the nearest they can, which is to say that the identifier arguments always refers to arguments magic and the identifier eval always exclusively refers to eval magic.
It could also improve the possibilities for optimisation, if JS engines can be sure whether a function contains magic.

Categories

Resources