How to prevent accidental pollution of global namespace with javascript eval?

I am writing a simple REPL implementation (Read, Evaluate, Print, Loop) in JavaScript. I can isolate the code and the calling context as follows:

var sandbox = { // Allow the input code to use predefined helper functions // without the preceding use of the this keyword. helper_fn: function() { alert("foo"); } }; var func = new Function("with (this) { " + user_inputed_code + " }"); func.call(sandbox); 

Now it closes user_inputed_code , so this refers to the sandbox , and if the entered code accesses or mutates this , it affects the sandbox .

However, I noticed that if the imputed code should have accidentally forgot to precede the variable assignment with the var keyword, the global namespace will be polluted.

Is there anyway to prevent this? If so, how (maybe a regular expression?)? Is there a better way to approach this?

+4
source share
2 answers

I am going to provide two completely different approaches to what others have discussed here. Both of them are harsh and useful when you want to relatively isolate your environment.

  • The easiest way that works in all browsers is probably to create an iframe and add script tags to it. (Note that a really overly complicated iframe can still pass by if they are in the same domain, at least in older browsers). I am discussing this in this matter .
  • Use web workers who have a default sandbox and do not have access to the global main thread object. I am discussing this in this matter .

In particular, if you are building a REPL, look at this answer where we are discussing, and I will explain how the eval code is in the same area, but outside the global scope, using the first iframes approach.

(I assumed a browser, in node you can just use the vm module and select a context in runInContext)

+2
source

It turns out there is a way with "use strict" and without Object.freeze . You must manually replace the global namespace with your own sandbox object:

 var sandbox, module, func, output; // Empty object or with defined methods / properties // you want to expose as globals. sandbox = {}; // A reference to an object you WANT to provide safe // access to. In this example it just an empty object. module = {}; // A better version of eval: func = new Function("module", "with(this){return(function(module,global,window){\"use strict\";return eval(\"" + code + "\");})(module,this,this)}"); output = func.call(sandbox, module); 

This code allows global and windows to refer to an isolated object instead of a global namespace. It masks the global and window variables as a sandbox object, and using "use strict" will throw an exception if the input skips using var . It also transfers the function to the with statement so that the methods and properties defined in the sandbox object work as if they were preceded by this. . To see an example implementation (with test specifications), review this meaning .

Thank you all for your ideas. Hope this answer helps others.

+1
source

Source: https://habr.com/ru/post/1493562/


All Articles