Compiling JS for Safe vm.runInNewContext()

322 views
Skip to first unread message

Kevin O

unread,
Jul 11, 2012, 12:52:05 PM7/11/12
to nod...@googlegroups.com
We are working on an app where we want to give users the ability to upload JS scripts to process their data in our app.

Insane, right? :)  Well we are going to do it in a sane way or not do it at all. We understand the risks.

I want to take raw JS input from the user, generate an AST, cleanse/evaluate/mangle it, then "re-compile" to minified JS only when we know is safe. If the script is doing unsafe things, we'll return compiler errors. Our compiler needs to be able to limit the JS globals to a short "whitelist". i.e. stuff like eval() is not available within the script. 

Scripts will be run in our node app using vm.runInNewContext(). We will pass in a context object with the data that the user will be processing with their script. 

Has anyone done something like this? I have a small bit of code started using uglify but am wondering if there are some other projects or design ideas I can pluck from before getting to deep into the weeds. 

Thanks

Kevin

Angel Java Lopez

unread,
Jul 11, 2012, 12:59:06 PM7/11/12
to nod...@googlegroups.com
I presented a project (idea, no code yet) that needs that feature, too.

Game server (as a service?) that accepts logic code from game tenants.
Another project needs something like this (it's like  https://github.com/ryanb/ruby-warrior/ )

So, thanks for the question, and for any answer!

Angel "Java" Lopez


Kevin

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to
nodejs+un...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

Marcel Laverdet

unread,
Jul 11, 2012, 1:17:23 PM7/11/12
to nod...@googlegroups.com
Look at Google Caja, this does exactly what you describe. It's a very complicated problem.

Vyacheslav Egorov

unread,
Jul 11, 2012, 2:21:16 PM7/11/12
to nod...@googlegroups.com
Even Caja does not try to deal with infinite loops I think. They only
deal (very successfully though) with information/capabilities leaks
and related attacks.

--
Vyacheslav Egorov

Kevin O

unread,
Jul 11, 2012, 2:24:40 PM7/11/12
to nod...@googlegroups.com
Thanks for the suggestion. Caja does seem like it's pretty robust but maybe more than I need. Plus, I would have to call out to a service every time I compile or re-implement the whole thing in node to use it. Neither is really an option, unfortunately.

On Wednesday, 11 July 2012 13:17:23 UTC-4, Marcel wrote:
Look at Google Caja, this does exactly what you describe. It's a very complicated problem.

On Wednesday, July 11, 2012, Angel Java Lopez wrote:
I presented a project (idea, no code yet) that needs that feature, too.

Game server (as a service?) that accepts logic code from game tenants.
Another project needs something like this (it's like  https://github.com/ryanb/ruby-warrior/ )

So, thanks for the question, and for any answer!

Angel "Java" Lopez

On Wed, Jul 11, 2012 at 1:52 PM, Kevin O <kevino...@gmail.com> wrote:
We are working on an app where we want to give users the ability to upload JS scripts to process their data in our app.

Insane, right? :)  Well we are going to do it in a sane way or not do it at all. We understand the risks.

I want to take raw JS input from the user, generate an AST, cleanse/evaluate/mangle it, then "re-compile" to minified JS only when we know is safe. If the script is doing unsafe things, we'll return compiler errors. Our compiler needs to be able to limit the JS globals to a short "whitelist". i.e. stuff like eval() is not available within the script. 

Scripts will be run in our node app using vm.runInNewContext(). We will pass in a context object with the data that the user will be processing with their script. 

Has anyone done something like this? I have a small bit of code started using uglify but am wondering if there are some other projects or design ideas I can pluck from before getting to deep into the weeds. 

Thanks

Kevin

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

On Wednesday, 11 July 2012 13:17:23 UTC-4, Marcel wrote:
Look at Google Caja, this does exactly what you describe. It's a very complicated problem.

On Wednesday, July 11, 2012, Angel Java Lopez wrote:
I presented a project (idea, no code yet) that needs that feature, too.

Game server (as a service?) that accepts logic code from game tenants.
Another project needs something like this (it's like  https://github.com/ryanb/ruby-warrior/ )

So, thanks for the question, and for any answer!

Angel "Java" Lopez

On Wed, Jul 11, 2012 at 1:52 PM, Kevin O <kevino...@gmail.com> wrote:
We are working on an app where we want to give users the ability to upload JS scripts to process their data in our app.

Insane, right? :)  Well we are going to do it in a sane way or not do it at all. We understand the risks.

I want to take raw JS input from the user, generate an AST, cleanse/evaluate/mangle it, then "re-compile" to minified JS only when we know is safe. If the script is doing unsafe things, we'll return compiler errors. Our compiler needs to be able to limit the JS globals to a short "whitelist". i.e. stuff like eval() is not available within the script. 

Scripts will be run in our node app using vm.runInNewContext(). We will pass in a context object with the data that the user will be processing with their script. 

Has anyone done something like this? I have a small bit of code started using uglify but am wondering if there are some other projects or design ideas I can pluck from before getting to deep into the weeds. 

Thanks

Kevin

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

For more options, visit this group at
http://groups.google.com/group/nodejs?hl=en?hl=en

--
Job Board: http://jobs.nodejs.org/
Posting guidelines: https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
You received this message because you are subscribed to the Google
Groups "nodejs" group.
To post to this group, send email to nod...@googlegroups.com
To unsubscribe from this group, send email to

Jeff Barczewski

unread,
Jul 11, 2012, 2:40:20 PM7/11/12
to nod...@googlegroups.com
https://github.com/tjanczuk/haiku-http is an interesting project that tries to provide a restartable/killable sandbox for running your code in node.js

This could help in dealing with bad code and even infinite loops.

I have not tried to use it yet, but flagged it as something I would look into when wanting to allow arbitrary code to be run on the server.

All the best,

Jeff

Mark S. Miller

unread,
Jul 11, 2012, 3:05:07 PM7/11/12
to nod...@googlegroups.com, Google Caja Discuss
[+google-caja-discuss]

On Wed, Jul 11, 2012 at 11:24 AM, Kevin O <kevino...@gmail.com> wrote:
Thanks for the suggestion. Caja does seem like it's pretty robust but maybe more than I need. Plus, I would have to call out to a service every time I compile or re-implement the whole thing in node to use it. Neither is really an option, unfortunately.

On Wednesday, 11 July 2012 13:17:23 UTC-4, Marcel wrote:
Look at Google Caja, this does exactly what you describe. It's a very complicated problem.


Caja as a whole secures JS, html, css, and the browser/dom API. On Node, the only relevant component is the securing of JS.

Caja has two ways to secure JS. 

  * For pre-ES5 systems, Caja uses a server-side translator to translate from the secure subset of ES5 to ES3. This is the "very complicated" that Marcel refers to.

  * For ES5 compliant systems, Caja uses a simple client-side translation-free system, the SES (Secure EcmaScript) library[1], to enforce that further code in that evaled in that context is limited to the object-capability subset of ES5.

Mark S. Miller

unread,
Jul 11, 2012, 3:08:03 PM7/11/12
to nod...@googlegroups.com, Google Caja Discuss
On Wed, Jul 11, 2012 at 12:05 PM, Mark S. Miller <eri...@google.com> wrote:
[+google-caja-discuss]

On Wed, Jul 11, 2012 at 11:24 AM, Kevin O <kevino...@gmail.com> wrote:

Thanks for the suggestion. Caja does seem like it's pretty robust but maybe more than I need. Plus, I would have to call out to a service every time I compile or re-implement the whole thing in node to use it. Neither is really an option, unfortunately.

On Wednesday, 11 July 2012 13:17:23 UTC-4, Marcel wrote:
Look at Google Caja, this does exactly what you describe. It's a very complicated problem.


Caja as a whole secures JS, html, css, and the browser/dom API. On Node, the only relevant component is the securing of JS.

Caja has two ways to secure JS. 

  * For pre-ES5 systems, Caja uses a server-side translator to translate from the secure subset of ES5 to ES3. This is the "very complicated" that Marcel refers to.

  * For ES5 compliant systems, Caja uses a simple client-side translation-free system, the SES (Secure EcmaScript) library[1], to enforce that further code in that evaled in that context is limited to the object-capability subset of ES5.

Forgot the punch line: Node is based on modern v8, and so is ES5 compliant. SES on Node should work fine.




--
    Cheers,
    --MarkM

Marcel Laverdet

unread,
Jul 11, 2012, 6:31:54 PM7/11/12
to nod...@googlegroups.com
"Too robust" is not a thing. This is a problem that is very complex. As mentioned in later replies by the Caja team and others since node is using a very modern version of v8 you can run Caja with minimal translations that are all done in pure-JS.

With regards to infinite loops you've got another thing on your hands. You will need to write some C++ code for this, but it's certainly possible to write a version of vm.runInNextContext() that has a timeout. Alternatively you could use a node process for each instance, and terminate with a SIGKILL.

Azer Koçulu

unread,
Jul 12, 2012, 2:03:17 PM7/12/12
to nod...@googlegroups.com
this may take your interest; http://github.com/azer/onejs

azer
>>>>> nodejs+un...@googlegroups.com
>>>>> For more options, visit this group at
>>>>> http://groups.google.com/group/nodejs?hl=en?hl=en
>>>>
>>>>
>>>> --
>>>> Job Board: http://jobs.nodejs.org/
>>>> Posting guidelines:
>>>> https://github.com/joyent/node/wiki/Mailing-List-Posting-Guidelines
>>>> You received this message because you are subscribed to the Google
>>>> Groups "nodejs" group.
>>>> To post to this group, send email to nod...@googlegroups.com
>>>> To unsubscribe from this group, send email to
>>>> nodejs+un...@googlegroups.com
>>>> For more options, visit this group at
>>>> http://groups.google.com/group/nodejs?hl=en?hl=en
>>
>>

Rehan Iftikhar

unread,
Jul 15, 2012, 12:46:29 PM7/15/12
to nod...@googlegroups.com
I'm really happy to hear that other people are thinking about these types of solutions too. I really believe that there are a whole class of applications/services that take in user written Javascript to accomplish some higher goal (data processing, filtering, etc.)

To that end I have been using my free time to build engine.js (https://github.com/rehanift/engine.js). I haven't had much free time lately so the docs might be a little stale, but the end-to-end tests should describe all of the module's functionality. It starts a process pool where it runs user-code (and SIGKILLS/restarts on execution timeout). It doesn't use Caja (though possibly in the future) nor does it use vm.runInNewContext() (it used to, but then I switched to using the contextify). I've tried to be conscious of security while building engine.js but I would not consider it 100% secure yet.

Reply all
Reply to author
Forward
0 new messages