Home > Web Front-end > JS Tutorial > body text

How to use the Node.js sandbox environment

php中世界最好的语言
Release: 2018-05-29 17:36:32
Original
2101 people have browsed it

This time I will show you how to use the Node.js sandbox environment, what are the precautions when using the Node.js sandbox environment, the following is a practical case, let’s take a look take a look.

\A common use case is to run the code in a sandboxed environment. The sandboxed code uses a different V8 Context, meaning that it has a different global object than the rest of the code.

Let’s look at an example first

const vm = require('vm');
let a = 1;
var result = vm.runInNewContext('var b = 2; a = 3; a + b;', {a});
console.log(result);  // 5
console.log(a);     // 1
console.log(typeof b); // undefined
Copy after login

The code executed in the sandbox environment has no impact on the external code, whether it is the newly declared variable b or the reassigned variable a. Note that the last line of code will be added with the return keyword by default, so there is no need to add it manually. Once added, it will not be silently ignored, but an error will be reported.

const vm = require('vm');
let a = 1;
var result = vm.runInNewContext('var b = 2; a = 3; return a + b;', {a});
console.log(result);
console.log(a);
console.log(typeof b);
Copy after login

As shown below

evalmachine.<anonymous>:1
var b = 2; a = 3; return a + b;
         ^^^^^^
SyntaxError: Illegal return statement
  at new Script (vm.js:74:7)
  at createScript (vm.js:246:10)
  at Object.runInNewContext (vm.js:291:10)
  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:17)
  at Module._compile (internal/modules/cjs/loader.js:678:30)
  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
  at Module.load (internal/modules/cjs/loader.js:589:32)
  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
  at Function.Module._load (internal/modules/cjs/loader.js:520:3)
  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
Copy after login

In addition to runInNewContext, vm also provides two methods, runInThisContext and runInContext, both of which can be used to execute code. runInThisContext cannot specify context

const vm = require('vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('localVar += "vm";');
console.log('vmResult:', vmResult);
console.log('localVar:', localVar);
console.log(global.localVar);
Copy after login

Because it cannot Accessing the local scope can only access the current global object, so the above code will report an error because it cannot find localVal

evalmachine.<anonymous>:1
localVar += "vm";
^
ReferenceError: localVar is not defined
  at evalmachine.<anonymous>:1:1
  at Script.runInThisContext (vm.js:91:20)
  at Object.runInThisContext (vm.js:298:38)
  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21)
  at Module._compile (internal/modules/cjs/loader.js:678:30)
  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
  at Module.load (internal/modules/cjs/loader.js:589:32)
  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
  at Function.Module._load (internal/modules/cjs/loader.js:520:3)
  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
Copy after login

If we change the code to be executed to direct assignment, it can run normally , but it also produces global pollution (global localVar variable)

const vm = require('vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('localVar = "vm";');
console.log('vmResult:', vmResult);  // vm
console.log('localVar:', localVar);  // initial value
console.log(global.localVar);     // vm
Copy after login

runInContext is different from runInNewContext in the context parameter passed in. The context object passed in by runInContext is not empty and must be passed through vm.createContext( ), otherwise an error will be reported. The context parameter of runInNewContext is optional and does not need to be processed by vm.createContext. Because runInNewContext and runInContext have a specified context, they will not cause global pollution like runInThisContext (no global localVar variables will be generated)

const vm = require('vm');
let localVar = 'initial value';
const vmResult = vm.runInNewContext('localVar = "vm";');
console.log('vmResult:', vmResult);  // vm
console.log('localVar:', localVar);  // initial value
console.log(global.localVar);     // undefined
Copy after login

When a sandbox environment is required to execute multiple script fragments, you can use multiple Call the runInContext method twice but pass in the same vm.createContext() return value implementation.

Timeout control and error capture

vm provides a timeout mechanism for the code to be executed. By specifying the timeout parameter, you can runInThisContext as an example

const vm = require('vm');
let localVar = 'initial value';
const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', { timeout: 1000});
Copy after login
vm.js:91
   return super.runInThisContext(...args);
          ^
Error: Script execution timed out.
  at Script.runInThisContext (vm.js:91:20)
  at Object.runInThisContext (vm.js:298:38)
  at Object.<anonymous> (/Users/xiji/workspace/learn/script.js:3:21)
  at Module._compile (internal/modules/cjs/loader.js:678:30)
  at Object.Module._extensions..js (internal/modules/cjs/loader.js:689:10)
  at Module.load (internal/modules/cjs/loader.js:589:32)
  at tryModuleLoad (internal/modules/cjs/loader.js:528:12)
  at Function.Module._load (internal/modules/cjs/loader.js:520:3)
  at Function.Module.runMain (internal/modules/cjs/loader.js:719:10)
  at startup (internal/bootstrap/node.js:228:19)
Copy after login

You can catch code errors through try catch

const vm = require('vm');
let localVar = 'initial value';
try { 
  const vmResult = vm.runInThisContext('while(true) { 1 }; localVar = "vm";', {
    timeout: 1000
  });
} catch(e) { 
  console.error('executed code timeout');
}
Copy after login

Delayed execution

In addition to executing code immediately, vm also You can compile it first and then execute it after a while. This requires mentioning vm.Script. In fact, whether it is runInNewContext, runInThisContext or runInThisContext, Script is actually created behind it. It can be seen from the previous error message. Next, we will use vm.Script to rewrite the example at the beginning of this article

const vm = require('vm');
let a = 1;
var script = new vm.Script('var b = 2; a = 3; a + b;');
setTimeout(() => { 
  let result = script.runInNewContext({a}); 
  console.log(result);   // 5 
  console.log(a);     // 1 
  console.log(typeof b);  // undefined
}, 300);
Copy after login

Except vm. Script and node are added in version 9.6. vm.Module can also be delayed in execution. vm.Module is mainly used to support ES6 modules, and its context is already bound when it is created. Regarding vm.Module, you still need to use flag on the command line to enable support for

node --experimental-vm-module index.js
Copy after login

vm as a sandbox environmentSafety?

vm is safer than eval because it isolates the current context, but it can still access the standard JS API and the global NodeJS environment, so vm It is not safe. This is mentioned in the official documentation

The vm module is not a security mechanism. Do not use it to run untrusted code

Please see below Example

const vm = require('vm');
vm.runInNewContext("this.constructor.constructor('return process')().exit()")
console.log("The app goes on...") // 永远不会输出
Copy after login

In order to avoid the above situation, the context can be simplified to only contain basic types, as shown below

let ctx = Object.create(null);
ctx.a = 1; // ctx上不能包含引用类型的属性
vm.runInNewContext("this.constructor.constructor('return process')().exit()", ctx);
Copy after login

To address this problem of native vm, someone developed the vm2 package, The above problems can be avoided, but it cannot be said that vm2 is necessarily safe

const {VM} = require('vm2');
new VM().run('this.constructor.constructor("return process")().exit()');
Copy after login

Although there is no problem in executing the above code, because the timeout of vm2 does not work for asynchronous code, the following code will never end execution. .

const { VM } = require('vm2');
const vm = new VM({ timeout: 1000, sandbox: {}});
vm.run('new Promise(()=>{})');
Copy after login

Even if you want to disable Promise by redefining Promise, there is still a way to bypass it

const { VM } = require('vm2');
const vm = new VM({ 
 timeout: 1000, sandbox: { Promise: function(){}}
});
vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');
Copy after login

I believe you have mastered the method after reading the case in this article. Please pay attention to php for more exciting things. Other related articles on the Chinese website!

Recommended reading:

Detailed analysis of the WeChat mini program introductory tutorial case

How to use http server in angularjs

The above is the detailed content of How to use the Node.js sandbox environment. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template