📜  Node.js VM 完整参考(1)

📅  最后修改于: 2023-12-03 15:03:14.709000             🧑  作者: Mango

Node.js VM 完整参考

Node.js VM (Virtual Machine) 是 Node.js 自带的一个可执行代码执行环境,可以在 Node.js 中创建隔离的 JavaScript 执行环境,使得代码在一个严格的沙盒中运行,避免了一些代码安全上的问题。以下是 Node.js VM 的完整参考。

创建一个隔离的沙盒环境
const { VM } = require('vm');

const vm = new VM();

vm.run(`
  const message = 'Hello, world!';
  console.log(message);
`);

以上代码会在 VM 中创建一个隔离的沙盒环境,并在沙盒中执行 JavaScript 代码,输出 Hello, world!

在 VM 中运行代码
runInContext()
const { createContext } = require('vm');

const context = createContext({ message: 'Hello, world!' });

const script = new vm.Script(`
  console.log(message);
`);

script.runInContext(context);

以上代码通过 createContext() 方法创建了一个上下文环境,定义了变量 message 的值为 Hello, world!。然后通过创建一个 vm.Script 对象,把 JavaScript 代码传入其中,并调用 runInContext() 方法运行该脚本,输出 Hello, world!

runInNewContext()
const script = new vm.Script(`
  console.log(message);
`);

script.runInNewContext({ message: 'Hello, world!' });

以上代码通过创建一个 vm.Script 对象,把 JavaScript 代码传入其中,并调用 runInNewContext() 方法运行该脚本,输出 Hello, world!。在 runInNewContext() 方法中,我们通过传入一个对象,来创建新的上下文环境。

runInThisContext()
const script = new vm.Script(`
  console.log(message);
`);

script.runInThisContext();

以上代码通过创建一个 vm.Script 对象,把 JavaScript 代码传入其中,并调用 runInThisContext() 方法运行该脚本,输出 ReferenceError: message is not defined 错误信息。这是因为 runInThisContext() 方法会在当前的上下文环境中运行代码,但当前的上下文环境中没有定义变量 message

在 VM 中编译代码
createScript()
const script = vm.createScript(`
  const message = 'Hello, world!';
  console.log(message);
`);

script.runInThisContext();

以上代码通过 vm.createScript() 方法编译 JavaScript 代码,返回一个 vm.Script 对象,然后调用 runInThisContext() 方法,在当前上下文环境中运行该脚本,输出 Hello, world!

在 VM 中使用沙盒环境

可以使用 vm.createContext()vm.runInContext() 创建一个沙盒环境,在该环境中执行 JavaScript 代码。以下是一个例子:

const sandbox = { message: 'Hello, world!' };
vm.createContext(sandbox);

vm.runInContext(`
  console.log(message);
`, sandbox);

以上代码创建了一个沙盒环境,定义了变量 message 的值为 Hello, world!,然后调用 vm.runInContext() 方法,在沙盒环境中执行 JavaScript 代码,输出 Hello, world!

在 VM 中设置上下文环境

可以使用 vm.createContext() 方法创建一个上下文环境,并通过 vm.setContext() 方法设置 VM 的全局上下文环境。以下是一个例子:

const context = vm.createContext({ message: 'Hello, world!' });
vm.setContext(context);

vm.runInThisContext(`
  console.log(message);
`);

以上代码创建了一个上下文环境,定义了变量 message 的值为 Hello, world!,然后通过 vm.setContext() 方法设置 VM 的全局上下文环境。最后调用 vm.runInThisContext() 方法,在当前上下文环境中执行 JavaScript 代码,输出 Hello, world!

在 VM 中使用 Module

可以使用 vm.createContext() 方法创建一个上下文环境,并在该环境中使用 require() 方法加载模块。以下是一个例子:

const fs = require('fs');
const vm = require('vm');
const path = require('path');

const context = vm.createContext({ require });
vm.runInContext(fs.readFileSync(path.join(__dirname, 'script.js')), context);

以上代码创建了一个上下文环境,并在该环境中使用 require() 方法加载 script.js 文件。

在 VM 中加强模块加载的安全性

VM 中的模块加载在默认情况下是不安全的,因为可以加载系统级模块或其他从网络上加载的模块,如果这些模块是不受信任的,就会导致代码安全问题。可以通过配置 VM,加强模块加载的安全性。以下是一个例子:

const { VM } = require('vm');
const vm = new VM({ 
  require: {
    external: true,
    builtin: ['path', 'fs'],
    root: './',
    modules: {
      'upper-case': {
        path: './node_modules/upper-case/index.js',
        module: require('upper-case')
      }
    }
  }
});

const result = vm.run(`
  const path = require('path');
  const upperCase = require('upper-case');

  const filepath = path.join(__dirname, 'test.txt');
  const content = upperCase('Hello, world!');

  require('fs').writeFileSync(filepath, content, 'utf8');
  content;
`);

以上代码中,我们通过创建一个 VM 对象时,传入一个配置对象来加强模块加载的安全性。在配置对象中,我们可以设置 external: true 以允许加载来自 VM 外部的模块,也可以设置 builtin: ['path', 'fs'] 以允许加载系统级模块以及一些特别的内置模块。我们还可以设置 root: './' 来指定模块的根目录,以及 modules 对象来提供自定义的模块。在以上代码中,我们提供了一个名为 upper-case 的自定义模块,该模块可以将字符串转为大写。

最后我们调用 vm.run() 方法,在沙盒环境中执行 JavaScript 代码,并返回大写的字符串。需要注意的是,代码中使用了 require() 方法来加载模块,并在 JavaScript 代码中编写了文件的写入操作,这个例子仅用于演示 VM 中的模块加载应该如何使用,实际操作中应考虑更多的安全性问题。