如何在 VM2 沙箱中使用节点模块

我试图在沙箱中运行用户提交的脚本来处理一些数据,然后通过 node-fetch 通过 http 请求将输出发送到指定的端点。但是,我不确定我是否做得正确,即使在阅读了 VM2 的文档之后,我也不能完全确定我需要配置哪些选项。

这是一个示例,我调用 process(); inputData 是 { a: 123 } ,userScript 将是如下所示的 sampleScript.js。

process(inputData, userScript) {
  const { NodeVM } = require('vm2');
  const vm = new NodeVM({
        console: 'inherit',
        sandbox: { content: inputData },
        require: { external: true },
        wrapper: 'none',
      });
  console.log(vm.run(userScript, 'node_modules'));
}

sampleScript.js

input = content;

function execute(data) {
  data['a'] *= 100;
  const fetch = require('node-fetch');
  await fetch(`webhook.site-endpoint`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
}
execute(input);

我应该期待指定端点上的消息“12300”。但是,await fetch 方法调用似乎有问题,因为我在控制台上收到此错误:

(节点:36376)UnhandledPromiseRejectionWarning:错误:在 TCPConnectWrap.afterConnect [as oncomplete] (net.js:1141:16) (node:36376) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag --unhandled-rejections=strict (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode 处连接 ECONNREFUSED 127.0.0.1:80)。

这可能只是我配置沙箱选项的方式,因为我不确定我是否首先成功导入了 node-fetch 库。任何意见,将不胜感激!

stack overflow How to use node modules inside VM2 sandbox
原文答案

答案:

作者头像

您通过传递 node_modules 作为第二个参数成功导入了模块,前提是您的 node-fetch 中有 node_modules

另一方面,错误是说在处理承诺时出现错误但未处理( await 被错误使用)。

该错误还表示连接被拒绝,这意味着 node-fetch 尝试连接,因此 node-fetch 工作正常。问题可能出在 URL 上。

问题出在代码上,我可以看出有几处是错误的。

  1. 你在不是 await 的函数中使用 async 。使用 async function execute(data){} 代替
  2. fetch 命令中可能存在错误,您应该通过将其包装在 catch 块中来 try-catch

更新后的代码应该是这样的

input = content;

async function execute(data) {
  try {
    data['a'] *= 100;
    const fetch = require('node-fetch');
    await fetch(`webhook.site-endpoint`, {
      method: 'POST',
      body: JSON.stringify(data),
    });
  }
  catch(err) {
    console.error(err)
  }
}
execute(input);