安全地执行任意代码作为子查询

时间:2014-01-12 15:56:11

标签: javascript node.js

我想将文本输入作为对象的子查询运行。

更好理解的例子:

//input: "all();"
collection.all(); //actual code ran

//input: "where({age: 10}).limit(10);"
collection.where({age: 10}).limit(10); //actual code ran

子查询可能包含的所有可能功能都是未知的,因此无法将其过滤掉。

最简单的解决方案是使用eval:

function run(subquery) {
    return eval('collection.' + subquery);
}

然而,这允许代码注入,例如:run('all();alert("dough!");');

如何安全地执行任意代码作为子查询?(也欢迎Node.js具体答案);

2 个答案:

答案 0 :(得分:0)

您可以使用VM module,它允许您在沙盒环境中执行JS。

有关示例,请参阅vm.runInNewContext示例。

根据您需要的变量,最安全的方法应该是将这些变量复制到新的上下文中,禁止脚本修改现有的上下文。

注意:这是Node.JS特有的,不适用于浏览器本身。

答案 1 :(得分:0)

由于@ adeneo的想法,我能够让它工作。我将输入解析为这样的数组:

//where({age: 10}).limit(10);
var track = [{fn: 'where', args: {age: 10}}, {fn: 'limit', args: 10}]

我可以使用括号表示法:

for (var key in stack) {
    var val = stack[key];
    result = result[val.fn].apply(this, val.args);
}

我用来解析初始执行的方法是:

function init() {
    var stack = [];
    function push(fn, args) {
        stack.push({
            fn: fn,
            args: args
        })  
    };
    return {
        foo: function () {
            push('foo', arguments);
            return db;
        },
        bar: function () {
            push('bar', arguments);
            return db;
        },
        stack: function () {
            return stack;
        }
    };
}
var db = init();
db.foo(1).bar({a: 5}).foo(false).stack();

这样做的一个缺点是它需要你定义每个可能的方法(foo和bar)。