Friday, August 24, 2018

Is there a way to restrict the access of child processes to my system in node.js?

Leave a Comment

I am trying to build a service to execute programs in different languages in node and give the output. So far I'm using the child_process's spawn for spawning commands.

let p = spawn('python',[sourceFilePath]); 

Is there a way so that I can limit the access of this child_process to my system so it can't access network,file system,etc ?

3 Answers

Answers 1

if it's Unix you can provide uid, gid of user/group with lower permissions:

var child = spawn(process, args, {     detached: true,     uid: uid,      gid: gid,      cwd: appDir,     stdio: [ 'ignore', 'pipe', 'pipe'] }) 

Answers 2

Node.js itself does not offer any mechanism to restrict child processes to only a subset of available resources other than setting the child process' UID/GID which might not be sufficient given your goal.

Note that remote code execution as a business model (ie. various *fiddle.org, online playgrounds etc.) are very difficult to make because it's a non-trivial task to protect the host operating system.

I will assume that your program will eventually run on a Linux server as that is the most common type of servers available nowadays for Node.js deployments. Covering this topic for all types of operating systems would be too broad and probably not that helpful.

Your goal

  • to execute a program with a user-provided input and return the output back to the user
  • restrict this program from accessing some or all I/O resources (file system, network, host OS information, memory etc.)
  • tolerate malicious users trying to do harm/extract information/compromise your server etc.

Node.js will not help here, at all. Node can spawn a child process, but that's about it. It does not control any of those I/O resources. The kernel does. We must look to what features the Linux kernel offers in this area.

I found a very detailed article about Linux sandboxing which I will use as a source of inspiration. If you are interested I recommend you read it and search for similar ones.

Low-level: Linux namespaces

Linux kernel offers low-level mechanisms to isolate processes in/from various system resources. You might want to check them out although I feel this is too low-level for your use case.

Firejail

Firejail is a tool to isolate a process for testing purposes from other system resources. I have never used it but it looks like it could be used for your use case.

Containers (ie. Docker)

Containers usually utilise Linux namespaces to create an environment which looks like a full operating system to the process running inside of them, even though they allow complete isolation from the host OS. You can restrict network access, filesystem access and even CPU/memory usage when running a program inside of a container.

Given your use case, I would probably go with container isolation as the community around them is quite huge nowadays which increases the likelihood of you finding the right support/documentation to achieve your goals.

Answers 3

You can use vm2 module for this.I also use that to run untrusted code by users.You can create sandbox to run user code and sandbox can access resources that only you specify to it. For example

    const vm = new VM({                                             sandbox: {                                                     console:console,                                                     timeout:200,                                                     fileName:fileName,                                                     cmdCommand:cmdCommand,                                                     url:url,                                                     exec:exec,                                                     input:inputs,                                                     imageName:imageName,                                                     reqs:reqs,                                                     resp:resp}                                             }); 

This can be your sandbox.User can use only that specific varibale that are listed above.For example if you remove console from above.Then user will not able to log.If they tries to do that code will through error.Late


vmCode = `var child = exec(cmdCommand,function(stderr, result) {                     console.log("done in exec")                     console.log(fileName)                     console.log(result)                      if(stderr){                 console.log("stderr")                 console.log(stderr)                 resp.send({"error":"Syntax error"})                 }                 else {                     console.log(result)                     }                    }             })` 

This is place where your child process code will be defined (as string)

Finally


vm.run(vmCode,(err)=>{             console.log("done")         }) 

This statement will execute code that is as string (vmCode is defined above)

In the documentation it is written that you can use this to run untrusted code. For more you can read from here https://www.npmjs.com/package/vm2

If You Enjoyed This, Take 5 Seconds To Share It

0 comments:

Post a Comment