【问题标题】:Combine NodeJS Fibers + VM Sandbox结合 NodeJS Fibers + VM Sandbox
【发布时间】:2017-04-24 12:47:54
【问题描述】:

我想在 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();

困难在于如何对代码进行沙箱化。不得不使用 Fibers 让事情变得非常复杂。我不确定如何开始。如何使用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 内运行,包括光纤和green_led 的实现等?
  2. 或者最好保持VM运行的代码最少,而不是以某种方式将green_ledsleep列入白名单/代理?在灰质上并不容易,首先要了解 Fibers 的工作原理已经够难了!

【问题讨论】:

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


    【解决方案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() 的字符串中定义,而虚拟机本身可以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) {}等。

    【讨论】:

      猜你喜欢
      • 2013-11-11
      • 2019-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-06-06
      • 2018-12-04
      • 1970-01-01
      • 2018-06-24
      相关资源
      最近更新 更多