让用户在nodejs

时间:2015-09-25 02:43:52

标签: javascript node.js handlebars.js eval

我有一个使用把手的节点js web应用程序。用户要求我让他们注册自己的车把助手。

我对让他们这样做非常犹豫......但如果有一种安全的方法,我会试一试。

var Handlebars = require("handlebars");
var fs = require("fs");
var content = fs.readFileSync("template.html", "utf8");


//This helper will be posted by the user
var userHandlebarsHelpers = "Handlebars.registerHelper('foo', function(value) { return 'Foo' + value; });"

//eval(userHandlebarsHelpers); This I do not like! Eval is evil

//Compile handlebars with user submitted Helpers
var template = Handlebars.compile(content);
var handleBarContent = template({ foo: bar });


//Save compiled template and some extra code.

提前谢谢!

2 个答案:

答案 0 :(得分:1)

因为帮助程序只是Javascript代码,所以您可以安全地从服务器上的外部世界运行任意Javascript的唯一方法是,如果您运行它是一个孤立的沙箱进程,或者您在运行它之前以某种方式清理了代码。

前者可以使用隔离的虚拟机和对进程的外部控制来完成,但这使得在某些外部进程中拥有帮助程序代码非常麻烦,因为您现在必须开发甚至调用它并来回传递数据的方法

当您的API集与node.js一样大时,清理Javascript以防止在您的服务器上运行漏洞是一项非常不可能完成的任务。浏览器有一套非常严格控制的东西,Javascript可以做些什么来保持底层系统不受浏览器Javascript的影响。 node.js没有这些安全措施。您可以将代码放在其中一个帮助程序中以擦除服务器的整个硬盘驱动器或安装多个病毒,或者几乎任何您想编码的恶意攻击。因此,运行任意Javascript根本就不安全。

根据需要解决的确切问题,可以开发一种数据驱动方法,用户可以提供一些更高级别的指令(而不是代码)(将其映射到该指令,用此替换,替换此有了它,显示这组数据等...)实际上不是Javascript,而是一些不可执行的元数据。这样做更安全,因为你可以控制所有代理这些元数据的代码,这样你就必须确保处理元数据的代码不能被欺骗做坏事。

答案 1 :(得分:0)

关注@ jfriend00输入,经过一些严肃的测试后,我找到了一种方法,使用nodejs vm模块。

用户将使用以下格式输入他们的助手:

[[HBHELPER 'customHelper' value]]
   value.replace(/[0-9]/g, "");
[[/HBHELPER]]

[[HBHELPER 'modulus' index mod result block]]
   if(parseInt(index) % mod === parseInt(result))
      block.fn(this);
[[/HBHELPER]]

//This will throw an error when executed "Script execution timed out."
[[HBHELPER 'infiniteLoop' value]] 
   while(1){}
[[/HBHELPER]]

我将该块翻译成这个并执行它:

 Handlebars.registerHelper('customHelper', function(value) {
    //All the code is executed inside the VM
    return vm.runInNewContext('value.replace(/[0-9]/g, "");', {
        value: value
    }, {
        timeout: 1000
    });
});

Handlebars.registerHelper('modulus', function(index, mod, result, block) {
    return vm.runInNewContext('if(parseInt(index) % mod === parseInt(result)) block.fn(this);', {
        index: index,
        mod: mod,
        result: result,
        block: block
    }, {
        timeout: 1000
    });
});

Handlebars.registerHelper('infiniteLoop', function(value) {
    //Error
    return vm.runInNewContext('while(1){}', {
        value: value
    }, {
        timeout: 1000
    });
});

到目前为止,我做了多次测试,尝试删除文件,需要模块,无限循环。一切都很顺利,所有这些操作都失败了。

在VM中运行把手助手回调函数是让我能够工作的原因,因为使用VM并运行整个代码的主要问题是将这些助手添加到我的全局Handlebars对象中。

如果我找到了利用它的方法,我会更新。