在 Node.js 中,vm 模块是官方提供的内置模块,能够在独立的上下文环境中执行 JavaScript 代码,通过隔离执行环境的方式,避免不可信代码直接访问宿主进程的全局对象和资源,是处理不可信代码执行场景的常用方案。

vm 模块核心 API 介绍
vm 模块提供了多个用于创建上下文和执行代码的方法,常用的核心 API 如下:
- vm.createContext(contextObject):创建一个沙箱上下文对象,该对象会作为不可信代码执行时的全局对象,默认情况下不包含 Node.js 的全局 API。
- vm.runInContext(code, contextifiedObject, options):在指定的沙箱上下文中执行代码,代码的全局作用域绑定到该上下文对象。
- vm.runInNewContext(code, contextObject, options):创建新的上下文并执行代码,等价于先调用 createContext 再调用 runInContext。
- vm.Script:用于预编译代码,可重复在多个上下文中执行,提升执行效率。
基础沙箱执行示例
以下是一个最简单的使用 vm 模块执行不可信代码的示例,仅提供基础的上下文环境:
const vm = require('vm');
// 定义沙箱上下文,仅包含允许不可信代码访问的变量
const sandbox = {
a: 1,
b: 2,
console: console // 允许代码使用 console 输出,也可以按需限制
};
// 将普通对象转换为上下文对象
vm.createContext(sandbox);
// 要执行的不可信代码
const untrustedCode = `
const sum = a + b;
console.log('计算结果:', sum);
sum;
`;
// 在沙箱中执行代码
const result = vm.runInContext(untrustedCode, sandbox);
console.log('执行返回值:', result);
构建安全的沙箱上下文
执行不可信代码时,需要严格控制沙箱上下文的内容,避免暴露敏感能力,以下是安全配置的核心要点:
1. 限制全局对象访问
不要在沙箱上下文中挂载 process、require、Buffer 等 Node.js 核心全局对象,否则不可信代码可能通过这些对象操作文件系统、发起网络请求或者退出进程。
2. 按需提供有限 API
如果不可信代码需要特定能力,仅提供最小权限的 API,例如仅允许计算时,不要提供任何 IO 相关的接口:
const vm = require('vm');
// 仅提供计算所需的变量,不挂载任何额外 API
const safeSandbox = {
Math: Math, // 允许使用数学计算能力
parseInt: parseInt // 允许类型转换
};
vm.createContext(safeSandbox);
const code = `
const num = parseInt('123');
const result = Math.pow(num, 2);
result;
`;
const res = vm.runInContext(code, safeSandbox);
console.log('安全执行结果:', res);
3. 设置超时时间
不可信代码可能存在死循环,需要通过 options 设置超时时间,避免阻塞宿主进程:
const vm = require('vm');
const sandbox = {};
vm.createContext(sandbox);
const infiniteLoopCode = `
while(true) {
// 死循环代码
}
`;
try {
// 设置超时时间为 1000 毫秒,超时后抛出错误
vm.runInContext(infiniteLoopCode, sandbox, { timeout: 1000 });
} catch (err) {
console.log('执行超时:', err.message);
}
使用 vm.Script 预编译代码
如果需要多次执行同一段不可信代码,可以使用 vm.Script 预编译代码,提升执行效率:
const vm = require('vm');
// 预编译代码
const script = new vm.Script('a + b');
// 第一个上下文执行
const sandbox1 = { a: 10, b: 20 };
vm.createContext(sandbox1);
const res1 = script.runInContext(sandbox1);
console.log('第一次执行结果:', res1);
// 第二个上下文执行
const sandbox2 = { a: 30, b: 40 };
vm.createContext(sandbox2);
const res2 = script.runInContext(sandbox2);
console.log('第二次执行结果:', res2);
vm 模块的安全边界说明
需要注意 vm 模块并不是绝对安全的沙箱,存在以下限制:
- 如果沙箱上下文包含了某些可以访问宿主环境的能力,例如挂载了可以操作原型链的方法,不可信代码可能通过原型链污染突破沙箱限制。
- vm 模块无法完全隔离 V8 引擎层面的漏洞,因此不能用于执行完全不可信的恶意代码,仅适合处理低风险的第三方代码片段。
- 不要将 vm 模块作为唯一的安全防护手段,对于高安全要求的场景,需要结合进程隔离、容器隔离等更严格的方案。
重要提醒:永远不要将 process、require 等敏感对象挂载到沙箱上下文中,也不要信任不可信代码的任何输入,所有传入沙箱的数据都需要先做校验。
完整安全执行示例
以下是一个完整的、相对安全的不可信代码执行示例,包含了上下文限制、超时设置、错误捕获:
const vm = require('vm');
/**
* 安全执行不可信代码的方法
* @param {string} code 不可信代码字符串
* @param {object} customContext 自定义允许的上下文变量
* @param {number} timeout 执行超时时间,单位毫秒
* @returns {any} 代码执行返回值
*/
function safeRunUntrustedCode(code, customContext = {}, timeout = 1000) {
// 构建基础沙箱,仅包含允许的 API
const sandbox = {
console: {
log: (...args) => console.log('[沙箱输出]', ...args),
error: (...args) => console.error('[沙箱错误]', ...args)
},
// 合并自定义上下文,自定义上下文会覆盖默认的同名属性
...customContext
};
// 转换为上下文对象
vm.createContext(sandbox);
try {
// 执行代码,设置超时
const result = vm.runInContext(code, sandbox, { timeout });
return result;
} catch (err) {
console.error('代码执行失败:', err.message);
return null;
}
}
// 测试执行
const testCode = `
const x = 5;
const y = 3;
const total = x * y;
console.log('x * y 的结果是', total);
total;
`;
const execResult = safeRunUntrustedCode(testCode, { x: 5 }, 500);
console.log('最终执行结果:', execResult);
Node.jsvm_modulesandboxuntrusted_code修改时间:2026-07-19 15:03:30