0

How can I strictly limit scope? I have tried wrapping and the Function class, but even though I can block self, window and globalThis by creating scope variables with the same names. Their items still persist and are usable within that code block.

One example which should be overkill but still allows self.location to be accessed.

(function () {
  "use strict";
  const foo = new Function('', "'use strict';const window=null, self=null, globalThis=null;console.log('global containers...',window,self, globalThis);return location");
  console.log(foo());
})()

This produces....

global containers... null null null
Location {...}

...in google chrome. I want to understand how to limit or block scope from the general containing environment.

How can I have only my local scope available for block or function code?

Ismael Harun
  • 143
  • 2
  • 7
  • Are you asking how to sandbox an arbitrary chunk of code? (Rather than how to write good quality code that won't try to set globals in the first place?) – Quentin Dec 02 '19 at 16:27
  • 1
    @Quentin I am trying to limit access to most of the global native objects. My quality is not really in the scope of my question because this is about using 3rd party entrusted code, which I would a way to wrap to prevent potential bleeding or malicious injection. Any helpful thoughts or strategies for that are welcome or suggestions of other ways to isolate entrusted code are welcome. – Ismael Harun Dec 02 '19 at 16:35
  • 1
    @IsmaelHarun Have you looked around sandboxing ? Maybe this question can be a starting point : https://stackoverflow.com/questions/195149/is-it-possible-to-sandbox-javascript-running-in-the-browser – Seblor Dec 02 '19 at 16:37
  • @Seblor Thanks, that looks helpful. I am giving it a read. – Ismael Harun Dec 02 '19 at 16:42

1 Answers1

0

To my knwoledge there is no way to prevent access variables from the global scope in the browser - other than setting to undefined every variable you don't want the script to access.

Here is a clean way to do so with an IIFE :

(function({window, self, location, globalThis}) {
  .. your code ..
})({
  window: undefined,
  self: undefined,
  location: undefined,
  globalThis: undefined
)}

If you target only some global variables, this technique is ok. Not ideal of course, but ok.

If you want to prevent access to every window variable, here is a hack :

We want to use a replacement of the new Function, but that creates an empty environment, like so :

var add = new StrictScopeFunction(
  ['a', 'b'],
  'console.log(typeof window, typeof location, a + b)'
);
add(12, 24);  // print : undefined, undefined, 36

Here is the code for the StrictScopeFunction function :

const StrictScopeFunction = (function() {
  // we find *once* all window variables (because it's an heavy operation)
  const globals = ['window', 'globalThis'];  // list of variables you don't want 
  for (let prop in globalThis)
    globals.push(prop);

  return function(args=[], code="") {
    const strictScope = {};

    for (const prop of globals) {
      // if the global property is not an argument of the new function
      if (!args.includes(prop))
        strictScope[prop] = undefined;
    }

    const func = new Function('{'+ Object.keys(strictScope).join(',') +'}', ...args, code);
    return func.bind(null, strictScope);
  }
})();

As a final note, if you are under a Node environment, you can have a look at the vm standard module - or the vm2 package.

Gin Quin
  • 966
  • 7
  • 15
  • Waaahh.... very cool. of course, i will have to add back in a few of them but this could work. Node yes, that is much easier. But this is for browser. TYSM. – Ismael Harun Dec 02 '19 at 20:49
  • One thing though, it chokes with that many arguments. Still many don't need to be in there, so it's still an option. – Ismael Harun Dec 02 '19 at 21:18
  • Yup that's a lot of global variables :p There is no automatic way to know if a global needs to be in there, so you should target which ones you don't want and modify the `StrictScopeFunction` accordingly. Just put all the variable names you don't want in the `globals` array instead of looping through `globalThis`. – Gin Quin Dec 03 '19 at 09:43