nodejs:在沙箱中运行模块

时间:2015-08-20 08:41:30

标签: javascript node.js sandbox

我有这个回合制的NodeJs游戏应用程序,其中开发人员(任何人)可以提交玩家机器人。我的NodeJS应用程序将加载所有玩家并让他们互相对战。因为我对提交的代码一无所知,所以我需要在沙盒中运行它。

例如,以下不受信任的代码可能如下所示:

let history = [];

export default class Player {
    constructor () {
        this.history = [];
    }

    move (info) {
        this.history.push(info);
   }

   done(result) {
       history.push({result: result, history: this.history});
   }
}

现在,在我的主应用程序中,我想做类似

的事情
import Player1 from 'sandbox/player1';
import Player2 from 'sandbox/player2';
....

for (let outer = 0; outer < 10; outer ++) {
    let player1 = creeateSandboxedInstance(Player1);
    let player2 = creeateSandboxedInstance(Player2);
    for(let inner = 0; inner < 1000000; inner ++) {
        ...
        let move1 = player1.move();
        let move2 = player2.doMove();
        ...
    }
}

我希望沙盒/ creeateSandboxedInstance环境能够处理的是:

  • 播放器类不应授予对文件系统/互联网的访问权限
  • 玩家类不应该有权访问应用程序全局变量
  • 任何州都应该重置(如类变量)
  • 可能更多的东西:)

我认为我应该使用vm module。这样的事情可能是:

var vm = require('vm');

var script = new vm.Script('function move(info){ ... } ...', {conext});

var sandbox = script.runInNewContext();

script.move(..);  // or
sandbox.move(..);

但是,我无法让它工作,因此我可以调用move方法。有可能甚至可能吗?

1 个答案:

答案 0 :(得分:1)

不要自己这样做。使用现有库。如果您自己编写,则需要处理很多问题。例如:如何处理用户编写永无止境的for循环?

How to run untrusted code serverside?

如果您打算自己编写,那么是的,您将需要vm模块。

通过传入一个空的“沙箱”,您已删除了所有全局变量。

script.runInNewContext({});

接下来,您需要弄清楚如何处理永无止境的for循环。您必须创建一个新流程来处理这种情况。您是否创建了1个进程来管理所有不受信任的代码?如果你这样做,那么如果一个脚本挂起,你将不得不杀死所有不受信任的代码。您是否为每个不受信任的代码创建了新流程?如果你这样做,你将不会对表现感到满意。创建新流程可能需要一两秒钟。您可以要求子进程“通知”它仍处于活动状态的主进程。如果它在5秒内未通知(或者无论您的阈值是什么,请终止该过程)。注意:script.runInNewContext确实包含一个允许您指定“超时”的选项(如果代码花费的时间超过X秒 - 抛出异常),但问题是它允许异步代码(根据另一个Stackoverflow帖子) ),虽然你可以通过不将setTimeoutsetIntervalsetImmediate引入范围来防御这种情况。但是,即使您将其设置为1秒,在该过程中的第二秒内也无法运行其他代码。因此,如果要运行1000个脚本,则最多可能需要1000秒(16分钟)才能运行它们。至少在他们自己的进程中运行它们将让它们并行运行。

以下是为什么超时选项不适合您的示例:

var script = new vm.Script('move = function move(info) { for(var i = 0; i < 100000; i++) { console.log(i); } }');
var sandbox = { move: null, console: console };
var result = script.runInNewContext(sandbox, { timeout: 1 });
sandbox.move('woah');

接下来,您需要弄清楚如何从主进程,子进程再到vm进行通信。我不打算在进程之间进行通信,因为你很容易找到它。因此,通过调用script.runInNewContext,您正在执行代码。这允许您设置全局变量:

var script = new vm.Script('move = function move(info) { console.log("test: " + info); }');
var sandbox = { move: null, console: console };
var result = script.runInNewContext(sandbox);
sandbox.move('success');