5

I'm working on react-metaform, and one of my challenges is that I need to allow the end-user to define metadata as functions. Example:

socialSecurityNumber.required: (m) => m.type == 'person'

The problem is obvious: I cannot trust the user. So, these are the precautions i'm planning to make:

  • User-defined functions should be pure function. In the sense that, these functions can only access their parameter, nothing else.
  • User-defined functions will run in an environment that is resilient to exceptions, too long execution times and infinite loops. (I'm not worried about this right now).

The question is: How do I make sure a user-defined function only accesses it's parameters and nothing else?

Andre Pena
  • 52,662
  • 43
  • 183
  • 224
  • 3
    I would assume your best bet is to define your own expression language that is parsed and then evaluated on your actual objects, rather than using `new Function`. – Bergi Oct 13 '15 at 16:21
  • 2
    http://stackoverflow.com/questions/14889393/how-to-run-a-javascript-function-in-a-sandbox-environment – epascarello Oct 13 '15 at 16:21
  • 2
    I think from the moment you are asking the user to write JS and execute it you are pretty much done for. You can't prevent long execution times (run-to-completion, yeah!) or make sure that the function is pure (maybe with massive shadowing through the parameters, but that would be weird). – Kyll Oct 13 '15 at 16:22
  • So far as I know you can't lock the local scope of the function. Some things can be done as explained here http://stackoverflow.com/questions/6083597/how-do-i-lock-a-javascript-function-to-the-local-scope-i-want-to-prevent-it-fr but it's probably not a walk in the park and i don't think you can close everything. – tgo Oct 13 '15 at 16:23
  • I see. Thanks all for the help. Maybe I should define my own expression syntax but that will not be easy... =/ – Andre Pena Oct 13 '15 at 16:25
  • You can lock down the function's environment to a significant degree now with ES2015 (and V8 supports many of the necessary features already), preventing it from accessing or creating globals by putting it in its own module in strict mode and calling it with `this` set to `undefined`. You'd still have the infinite loop problem, though, which can only be solved with a child process. – T.J. Crowder Oct 13 '15 at 16:25
  • @T.J.Crowder. Thanks. Does that work on the browser? – Andre Pena Oct 13 '15 at 16:26
  • @andrerpena: Depends on how well the browser's JavaScript engine supports ES2015. But you tagged this `node.js` so I assumed V8. – T.J. Crowder Oct 13 '15 at 16:27
  • @T.J.Crowder. I see. Actually I ned to run it on Node.js and on browsers too. But good point. I'm gonna look into this. – Andre Pena Oct 13 '15 at 16:35

1 Answers1

1

I would use esprima to parse users' JavaScript functions that are stored in files or in a database. And I would allow to run only code that passes the parsing test (only whitelisted features - using local variables, parameters, ...).

You can start with a very simple checking code that only allows very limited scripts and progressively improve it. However, I guess you will put a lot of effort to the solution over time because your users will always want more.


Note: Angular.js uses for its dependency injection this kind of 'trick': https://jsfiddle.net/987Lwezy/

function test() {
   console.log("This is my secret!");
}


function parser(f) {
    document.body.innerHTML = test.toString();
}

parser(test);
MartyIX
  • 26,515
  • 27
  • 129
  • 197
  • 1
    Hm, how would this prevent something like `function() { [].__proto__.slice = function() { return "I've screwed you app!"; }; }` (which uses no free variables)? – Bergi Oct 25 '15 at 22:19
  • OP said he wants to allow only accessing user parameters. Assignment to `[].__proto__.slice` is not an assignment to user parameter. – MartyIX Oct 25 '15 at 22:26
  • Essentially, you have to either come up with a subset of JavaScript that you allow or choose another solution. It's absolutely crucial to use a "whitelist solution" and not a "blacklist solution". I mean you cant just forbid `eval` and hope for the best. You can enable only basic arithmetics with function parameters... for all I know it may suffice in some scenarios. – MartyIX Oct 25 '15 at 22:31
  • 3
    Ah, I see, you were only going to allow sideeffect-free expressions, so property access and assignment (especially in combination) would be severly limited. Makes sense. – Bergi Oct 25 '15 at 23:35