How to run untrusted code serverside?
I'm trying to run untrusted javascript code in linux + node.js with the sandbox module but it's broken, all i need is to let users write javascript programs that printout some text. No other i/o is allowed and just plain javascript is to be used, no other node modules. If it's not really possible to do, what other language do you suggest for this kind of task? The minimal feature set i need is some math, regexes, string manipulation, and basic JSON functions. Scripts will run for let's say 5 seconds tops and then the process would be killed, how can i achieve that?
All libraries I've seen mentioned in such questions (vm2
, jailed
) are trying to isolate the node
process itself. Those kind of "jails" are constantly broken and highly dependent on future upgrades to node
's standard library to not expose another attack vector.
An alternative would be to use the V8::Isolate
class directly. It is meant to isolate JavaScript in Google Chrome & node
, so you can expect it to be fully maintained, and more secure than you, I or a single library maintainer would ever be able to do.
This class is only able to run "pure" JavaScript
. It has the full ECMAScript implementation, but no browser API or node
API.
This is what is used by Cloudflare
for their Worker product.
deno
, the new language developed by node
's creator, has an ambition of sandboxing by default using exactly the same thing and exposing parts of the standard library depending on the flags you enable.
In a node
environment, you can use isolated-vm
. It's an amazing library that creates v8::Isolate
d subprocesses with the code you want to run in isolation.
It provides methods to pass values and functions to the isolate and back. This is not as trivial to use than most of the "jailing" libraries, but guarantees you an actual sandboxing of the JavaScript code.
As it's "pure" JavaScript, the only escapes are the ones you provide under the form of injected functions.
Also, it gets automatically updated with each node
version, as it uses node
's own v8::Isolate
.
One of the main pains is that if you want to inject libraries in your script, you will likely need to use a package bundler like webpack
in order to bundle everything in a single script that can be used by the library.
I personally use it to run user-provided code in a crawler to extract information from a webpage using user provided code, and it works wonders.
I've recently created a library for sandboxing the untrusted code, it seems to fit the demands (executes a code in a restricted process in case of Node.js, and in a Worker inside a sandboxed iframe for a web-browser):
https://github.com/asvd/jailed
There is an opportunity to export the given set of methods from the main application into the sandbox thus providing any custom API and set of privilliges (that feature was actually the reason why I decided to make a library from scratch). The mentioned maths, regexp and string -related stuff is provided by the JavaScript itself, anything additional may be explicitly exported from outside (like some function for communicating with the main application).
The basic idea of sandboxes is, you need variables predefined as globals to do stuff, so if you deny a script them by unsetting them, or replacing them with controlled one, it cannot escape. As long you don't forget anything.
First replace deny require() or replace it with something controlled. dont forget about process and "global" a.k.a "root", the difficult thing is not to forget anything, thats why its good to rely on someone else having built a sandbox ;-)
Docker.io Is an awesome new kid on the block, which uses LXCs and CGroups to create sandboxes.
Here is one implementation of an online gist (similar to codepad.org) using Docker and Go Lang
This just goes to demonstrate that one can safely run untrusted code written in many programming languages inside Docker Containers, including node.js