Node.js vm2中如何导入脚本?面向不可信代码的实现方案
安全在VM沙箱中执行不可信代码并实现模块复用的最佳方案
如果你要处理不可信的脚本B,同时让它安全复用脚本A里的MathFunctions,绝对不能用Node.js原生的vm模块——它的隔离性太弱,很容易被不可信代码绕过,进而访问宿主环境的敏感资源。业界针对这类场景的标准方案是用vm2,这是一个专门为不可信代码设计的安全沙箱库,能提供更强的隔离和权限控制。
下面是具体的实现步骤和代码示例:
1. 先安装vm2
首先在你的项目里安装这个库:
npm install vm2
2. 编写安全的沙箱执行代码
我们会把可信的脚本A封装成一个模拟模块,然后让不可信的脚本B只能通过指定路径导入这个模块,同时严格限制沙箱的权限,禁止它访问任何外部或内置资源:
const { NodeVM } = require('vm2'); // 第一步:定义我们的可信模块(对应脚本A) const trustedMathModule = ` class MathFunctions { add(a, b) { return a + b; } } // 用CommonJS导出,也可以改成ES模块格式 module.exports = MathFunctions; `; // 第二步:配置安全沙箱 const vm = new NodeVM({ console: 'inherit', // 可选:让沙箱可以输出日志到宿主控制台 sandbox: {}, // 初始化干净的沙箱,不暴露任何宿主全局变量 require: { external: false, // 禁止不可信代码访问外部npm模块 builtin: [], // 禁止访问Node.js内置模块(比如fs、http) mock: { // 把我们的可信模块模拟成一个可导入的本地模块 './trusted-math.js': trustedMathModule } } }); // 第三步:处理不可信的脚本B(修正了原代码的导入语法) const untrustedScriptB = ` const MathFunctions = require('./trusted-math.js'); const mf = new MathFunctions(); console.log(mf.add(2, 2)); // 会输出4 `; // 第四步:执行不可信代码并捕获错误 try { vm.run(untrustedScriptB); } catch (err) { console.error('执行不可信代码时出现异常:', err); }
3. 如果要支持ES模块的import语法
如果你的脚本B习惯用ES模块的import,可以修改vm2的配置来启用ES模块支持:
const vm = new NodeVM({ console: 'inherit', sandbox: {}, esm: { modules: true, // 启用ES模块 mock: { // 这里把可信模块改成ES导出格式 './trusted-math.js': ` export default class MathFunctions { add(a, b) { return a + b; } } ` } } }); // 脚本B改成ES模块语法 const untrustedScriptB = ` import MathFunctions from './trusted-math.js'; const mf = new MathFunctions(); console.log(mf.add(2, 2)); `;
关键注意事项
- 严格限制权限:一定要把
external和builtin都禁用,只开放你明确允许的资源,避免不可信代码逃逸沙箱。 - 避免暴露全局变量:不要把宿主的
process、global等对象传入沙箱,防止被利用。 - 错误捕获:用
try-catch包裹执行逻辑,避免不可信代码的异常导致整个宿主进程崩溃。
内容的提问来源于stack exchange,提问作者Robert Christian
相关产品推荐
相关产品推荐

