I've done some research on sandboxing in JavaScript and Node.js. Below
are some of my findings.

Seven Degrees of Sandboxing:

1. restrict direct read-access to not explicitly white-listed
   properties of the global object
2. restrict direct write-access to the global object so that it
   cannot be extended
2. restrict direct write-access to the global object so that its
   properties cannot be mutated
4. strict mode: lexical scoping (yay!), no global object
5. strict mode with frozen context
6. strict mode with frozen context, running as a separate process
7. strict mode with frozen context, running as a separate process in a
   chroot environment or jail

Note that without lexical scoping (i.e., in unrestricted mode) proper
sandboxing is conceptionally hard, and in practice maybe even
impossible. For instance, a function can access properties that are
outside of its scope via `arguments.callee`. In an environment like
Node.js, there are probably several other ways to do so.

In strict mode, sandboxing is probably pretty straight-forward. For
instance, a function `runInSandbox` that executes some other function in
a sandbox with a frozen context and no global object could be as
follows:

function runInSandbox(src, ctx) {
  var vm = require('vm'),
    sandbox = Object.freeze(vm.createContext(ctx || {})),
    script = vm.createScript('(function() {"use strict"; return (' + src
+ ')()}())');
  return script.runInContext(sandbox);
}

With such type of sandboxing function, we can put our own secure version
of `require` into the sandbox's context. When called, that secure
require function would check against a black or white list whether that
module is secure and can be required, and then according to that either
require the module or throw an exception.

Would it be an issue for you to constrain the execution of JavaScript to
be in strict mode only by default?


On Thu, 2013-01-31 at 16:54 +0000, Jason Smith wrote:
> On Thu, Jan 31, 2013 at 4:34 PM, Benoit Chesneau <bchesn...@gmail.com>wrote:
> 
> >
> > A javascript engine doesn't expose any IO par default. The **framework**
> > nodejs is, this is all the point. I'm quite interested by the existing
> > solutions to sandbox nodejs, do you know some projects that does it?
> >
> 
> Correct. I am attempting to build something which satisfies your
> description: no i/o; i/o is not even possible.
> 
> *How* is it implemented? Well, it doesn't matter whether we use Node.js or
> couchjs/SM or couchjs/v8. What matters is we feel confident about security.
> And of course, I agree, if we cannot achieve good security, then that is a
> show stopper.
> 
> Here is my current plan for sandboxing CouchJS. (Thanks to Isaac for his
> tips.)
> 
> When it is time to evaluate some code:
> 
> 1. Set up an object with safe variable bindings: safe_context
> 2. fork()
> 3. Child process runs vm.runInNewContext(safe_context)
> 4. Child process communicates to the parent over stdio, through the
> approved safe_context functions
> 
> The subprocess can also give extra sandboxing, such as chroot() if
> available.
> 
> Yes, this causes two processes per instantiation; however I think the
> parent might only be short-lived, setting up the security, then exiting.
> The grandchild can talk to Erlang over stdio.
> 
> That is my plan. No idea how well it will work.
> 


Reply via email to