结合NodeJS Fibers + VM Sandbox
我想在Node中运行一些不受信任的代码,如下所示:
for (var i = 0; i < 5; i++){ green_led(1); sleep(500); green_led(0); sleep(500); }
使用光纤,我得到了同步行为按预期工作:
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_led
和sleep
对虚拟机中的沙盒代码不可见)。
这应该怎么做? 要么…
- 也许一切都应该在虚拟机内运行,包括光纤和
green_led
实施等? - 或者,最好是保持虚拟机运行的代码最小,而不是白名单/代理
green_led
和sleep
? 在灰色的问题上不是很容易,很难理解纤维如何在第一位工作!
其实挺简单的
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
的引用,其他函数通过沙箱对象sleep
和green_led
。 这可以通过其他方式来完成。 例如,可以在传递给vm.run()
的string中定义sleep
和green_led
,并且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()` );
根据文档 ,请注意VM
和NodeVM
之间的区别。 在以上两种方法中,只有第一种方法能够使用超时function。 另外,第二种方法对while (true) {}
等不是免疫的