Can I limit the access of a string-generated function (using the Function constructor) to the parent/global scopes?
For example: the following code, as it is, prints false, because the function is storing/modifying the variable a in window.
window.a = 4;
Function("a=3;")()
console.log(a === 4);
Could I restrict the access to window/parent scope and make it print out "true"?
Here is an additional idea which could be quite powerful together with Esailija's proposal (see the comments on his answer for the discussion).
You could create dummy iframe and use its Function
function. The function created with that will only have access to the scope of the iframe by default, though it could still break out of it. Fortunately it is easy to prevent that, by the way Esailija suggested.
I could imagine the function to be like this:
function sandboxed(code) {
var frame = document.createElement('iframe');
document.body.appendChild(frame);
var F = frame.contentWindow.Function,
args = Object.keys(frame.contentWindow).join();
document.body.removeChild(frame);
return F(args, code)();
}
DEMO
Optionally you might want to prepend 'use strict';
to the code.
This works at least in Chrome. Whether the function created this way has access to the iframe's global scope or the page's global scope can be easily tested with:
(function() {
var frame = document.createElement('iframe');
document.body.appendChild(frame);
var same = window === frame.contentWindow.Function('return window;')();
alert(same ? ':(' : ':)');
document.body.removeChild(frame);
}());
I don't think so. You could name the globals you want to protect in the parameters so that they shadow them:
window.a = 4;
Function("a", "a=3;")()
console.log(a === 4);
But the function is going to have access to global no matter what you try... that's why it's called global.
Depending on what you are trying to do, there are other work-arounds such as web workers... and as always, hidden iframe hacks.
@Esailija's answer is right. Additionally, I would recommend limiting the number of global variables that you have to protect in the first place. Put anything that you would normally put in the global namespace in an APP
scope that you control:
var APP = (function() {
return {
a: 4
};
}());
There's no way to completely limit access to the global scope, but at least this way you only need to protect one object: APP
.