NPM cool library, two minutes a day, learn about a popular NPM library.

Today’s library is VM2, a replacement to the official Node.js VM library that addresses security issues.

Unsecure VM

There is a VM library in the Node.js official standard library that compiles and executes JS code in a V8 virtual machine environment. Typically, we use VM libraries to implement a sandbox, executing additional JS scripts outside of the main code program.

Sometimes we need a VM virtual machine to execute untrusted code that might be submitted by a user, such as in Pulse Cloud Interface Document Management, which allows users to submit a mock.js script to generate Mock interface data. While the VM in the Node.js standard library is not secure, user scripts can easily break through the sandbox environment and get the Context of the main application!

const vm = require('vm');
vm.runInNewContext('this.constructor.constructor("return process")().exit()');
console.log('Never gets executed.');

When the above code is executed, the program exits directly on the second line. The code in the VM virtual machine environment escapes, obtains the process variable of the main thread, and calls process.exit(), causing the main program to exit abnormally.

Reasons why VM is not secure

The code above uses shorthand for the RunInNewContext function, which is equivalent to the following code:

const vm = require('vm');

const sandbox = {};
const script = new vm.Script('this.constructor.constructor("return process")().exit()');
const context = vm.createContext(sandbox);

script.runInContext(context);

console.log('Never gets executed.');

We can see from the code that when we create a VM environment, we first initialize an object called sendbox. This object is the global Context in which the VM script is executed. The global this object in the VM script refers to this object.

Scripting in VM is equivalent to:

const sandbox = this; // get Context const ObjectConstructor = this.constructor; / / access Object constructor const FunctionConstructor = ObjectConstructor. The constructor; // get const myfun = FunctionConstructor(' FunctionConstructor '); // create a function that returns the global process variable const process = myfun(); process.exit();

You can see why the VM is not secure from the above script. The Context object of VM internal script is defined in the main program. According to the principle of JS prototype chain, it is easy to obtain the Function object in the main program and construct a Function with the Function object of the main program. Then, when the Function is run, it is executed in the closure environment of the main program! So, we easily get to the main program of the global object Process, the final control of the main program!

The safety of vm2

VM2 was created specifically to solve the security problems of VMs.

const { VM } = require('vm2');
const vm = new VM({
    timeout: 1000,
    sandbox: {}
});

vm.run(`process.exit()`); // TypeError: process.exit is not a function

Vm2 features:

  • Run untrusted JS scripts
  • The terminal output information of the sandbox is completely controllable
  • Modules can be loaded in a sandbox in a limited way
  • Callbacks can be passed safely between sandboxes
  • Infinite attack immunitywhile (true) {}

Vm2 principle:

First, VM2 is VM-based, using the official VM library to build the sandbox environment. Then use JavaScript’s Proxy technology to prevent sandbox scripts from escaping.

The resources

VM2 https://github.com/patriksime…

Proxy https://developer.mozilla.org…

Welcome to pay attention to public number: Liang Xingchen

Learn an NPM library every day and become a Node.js master in a year