结合NodeJS光纤+ VM沙箱

时间:2016-12-09 05:28:01

标签: node.js node-fibers nodevm node-vm2

我想在Node中运行一些不受信任的代码,可能如下所示:

for (var i = 0; i < 5; i++){
    green_led(1);
    sleep(500);
    green_led(0);
    sleep(500);
}

使用Fibers,我得到了同步行为正常工作:

var Fiber = require('fibers');

function sleep(ms){
    var fiber = Fiber.current;
    setTimeout(function(){ fiber.run(); }, ms);
    Fiber.yield();
}
function green_led(active){
    //...
}
Fiber(function(){
    for (var i = 0; i < 5; i++){
        green_led(1);
        sleep(500);
        green_led(0);
        sleep(500);
    }
}).run();

困难在于如何沙箱代码。不得不使用光纤使它变得非常复杂;我不确定如何开始。我如何使用vm2获取上述沙箱?例如,以下显然不起作用:

var code = "\
for (var i = 0; i < 5; i++){\
    green_led(1);\
    sleep(500);\
    green_led(0);\
    sleep(500);\
}\
";
function sleep(ms){
    var fiber = Fiber.current;
    setTimeout(function(){ fiber.run(); }, ms);
    Fiber.yield();
}
function green_led(active){
    //...
}
Fiber(function(){
    vm.run(code);
}).run();

(由于green_ledsleep对VM中的沙盒代码不可见,因此无效。

应该怎么做?要么...

  1. 也许一切都应该在VM内部运行,包括Fibers和green_led等的实现?
  2. 或者最好让VM最少运行代码,而不是以某种方式将白名单/代理green_ledsleep?灰色问题并不容易,因此很难理解Fibers的工作方式!

1 个答案:

答案 0 :(得分:1)

实际上非常直接。

var Fiber = require('fibers');

const {VM} = require('vm2');
const vm = new VM({
    sandbox: {
        green_led: green_led,
        sleep: sleep
    }
});

function sleep(ms){
    var fiber = Fiber.current;
    setTimeout(function(){ fiber.run(); }, ms);
    Fiber.yield();
}
function green_led(active){
    //...
}

vm.run(
    `Fiber(function(){
        for (var i = 0; i < 5; i++){
            green_led(1);
            sleep(500);
            green_led(0);
            sleep(500);
        }
    }).run()`
);

上述方法通过沙盒对象传递对Fiber和其他函数sleepgreen_led的引用。这可以通过其他方式完成。例如,sleepgreen_led可以在传递给vm.run()的字符串中定义,而vm本身可以include fibers,如下所示:

const {NodeVM} = require('vm2');
var vm = new NodeVM({
    require: {
        external: true,
    }
});
vm.run(
    `
    var Fiber = require("fibers");
    function sleep(ms){
        var fiber = Fiber.current;
        setTimeout(function(){ fiber.run(); }, ms);
        Fiber.yield();
    }
    function green_led(active){
        //...
    }
    Fiber(function(){
        for (var i = 0; i < 5; i++){
            green_led(1);
            sleep(500);
            green_led(0);
            sleep(500);
        }
    }).run()`
);

根据the documentation,请注意VMNodeVM之间的差异。在上述两种方法中,只有第一种方法能够使用超时功能。此外,第二种方法不能免疫while (true) {}等。