How to Run Untrusted Code Serverside

I need to run untrusted server-side code in a web app - what are my options?

Here are a few ways you can run untrusted code:

  • a docker container that runs the code, I would suggest checking codecube.io out, it does exactly what you want and you can learn more about the process here
  • using the libsandbox libraries but at the present time the documentation is pretty bad
  • PyPy’s sandboxing

JavaScript eval() on client-side for running untrusted code

If you have no path in your logic that allows one person to publish code to be used by others then you can use eval() as it is.

Your situation is not anyhow different from any user that has browser and dev tools in it where he/she can run any code they want.

Run untrusted code at Google Cloud Functions

If I understand your request correctly, you are looking to have Cloud HTTP Functions evaluate user-provided Javascript code on the server side.

By your description, the only real ways the function would be able to evaluate the user's code would be essentially using eval or new Function(). To confirm the risks I mentioned, I created a cloud function that simply passes the POST request body to eval. Without any dependencies, I could issue HTTP requests on behalf of the cloud function which could be quite bad.

Given that most useful cloud functions would have "@google-cloud" as a dependency, the user could gain access to that context. I was able to require @google-cloud and get all the information accessible to that object (application credentials, application information, etc.). Having such information available to a malicious user is considerably worse that the first test. In addition, Cloud Functions are authenticated by default, presumably by default application credentials, thus gaining all the abilities of the gcloud client library.

In the end, the safest way to run user-provided code on the server would be within a container. This would essentially lock the user's code into a Linux box where the resources and networking capabilities can be entirely governed by you. On the Google Cloud Platform, you're best means of accomplishing this would likely be using App Engine as a front-end to handle user requests and Compute Engine VMs to create and run containers for user code. It's more complex but doesn't risk destroying your Google Cloud Platform project.

Prevent system calls in Node.js when running untrusted user code

You are looking for the runInNewContext function from the vm module (vm documentation).

When you use this function it creates a VERY limited context. You'll need to pass anything you want into the sandbox object which become global objects. For example: You will need to include console in the sandbox object if you want your untrusted code to write to the console.

Another thing to consider: Creating a new context is a VERY expensive operation - takes extra time and memory to do. Seriously consider if you absolutely need this. Also seriously consider how often this is going to happen.

Example:

var vm = require('vm');
var sandbox = {
console: console,
msg: "this is a test",
};

vm.runInNewContext('console.log(msg);', sandbox, 'myfile.vm');

// this is a test

More to consider: You will want to create a new process to run this in. Even though it's in a new context it's still in the same process that it's being called from. So a malicious user could simply set a never ending for loop so that it never exits. You'll need to figure out logic to know when something like this happens so that you can kill the process and create a new one.

Last thought: A new context does not have setTimeout or setInterval. You may or may not want to add these. However, if you create a setInterval in the untrusted code and the untrusted code never stops it then it will continue on forever. You'll need to figure a way to end the script, it's probably possible I just haven't looked into it.

How to run user-submitted scripts securely in a node.js sandbox?

You should always run untrusted code in a separate process, which is exactly what the sandbox module does. A simple reason is that vm.runInNewContext('while(true){}', {}) will freeze node.

It starts by spawning a separate process, which will later send the result serialized to JSON on its stdout. The parent process continues executing regardless of what the child does and can trigger a timeout.

The untrusted code is then wrapped in a closure with strict mode (in regular JavaScript, you can use arguments.callee.caller to access data outside of your scope). Finally, a very limited global object is passed to prevent access to node's API. The untrusted code can only do basic computation and has no access to files or sockets.

While you should read sandbox's code as an inspiration, I wouldn't recommend using it as is:

  • The code is getting old and hasn't been updated for 7 months.
  • The Child Process module in node already provides most of the features you need, especially child_process.fork().
  • The IPC channel provided by child_process.fork probably has better performances.

For increased security, you could also consider using setuid-sandbox. It's the code used by Google Chrome to prevent tab processes from accessing the file system. You would have to make a native module, but this example seems straightforward.

Safely sandbox and execute user submitted JavaScript?

This answer is outdated as gf3 does not provide protection against sandbox breaking

http://gf3.github.io/sandbox/ - it uses require('child_process') instead of require('vm').



Related Topics



Leave a reply



Submit