0

在我的网络应用程序中,我想接受任意 JavaScript 对象作为 GET 参数。所以我需要以location.search类似于 的方式进行解析eval,但我只想创建自包含对象(对象文字、数组、正则表达式和可能的受限访问函数):

var search =
    location.search ?
    decodeURIComponent(location.search).substring(1).split('&') :
    ['boo=alert(1)', 'filter={a: /^t/, b: function(i){return i+1;}}']
;
var params = {};
for (var i = 0, temp; i < search.length; i++){
    temp = search[i].split('=');
    temp = temp[1] ? temp : [temp[0], null];
    params[temp[0]] = saferEval(temp[1]);
};
console.log(params);

我想出了一个saferEval阻止访问全局变量的函数版本,但它不会阻止访问内置函数,例如alert()

var saferEval = function(s) {
    'use strict';
    var deteleGlobals =
        'var ' +
        Object.getOwnPropertyNames(window)
          .join(',')
          .replace(/(?:eval|chrome:[^,]*),/g, '') +
        ';'
    ;
    try {
        return eval(deteleGlobals + '(' + s + ');') || s;
    } catch(e) {
        return s;
    };
};

请参阅我的jsFiddle -alert(1)代码已执行。 请注意,top.locationjsFiddle 脚本无法访问,如果您想使用实际的查询参数(如?filter={a: /%5Cd+/g}.

我会使用 JSON,但我需要在数组和对象内的任意位置使用正则表达式。我不会将这些对象中的任何一个发送回服务器,因此使用eval它不应该对安全性造成太大损害......

如何在不授予它访问全局命名空间和内置函数的权限的情况下将字符串(编码 JavaScript 对象)转换为对象?

更新 - 只有有用的“任意”对象原来是正则表达式文字......

4

2 回答 2

1

根据您的评论,您有兴趣看到一个解决方案,该解决方案只是解决在您的 JSON 中具有正则表达式值的问题,然后您可以将所有正则表达式值编码为普通 JSON 中的字符串,如下所示:

"/this is my regex/"

然后,将 JSON 正常处理为 javascript 对象,然后在其上调用此函数,该函数将递归遍历所有对象和数组,查找所有字符串项目,检查它们是否符合上述格式,如果找到,将这些项目转换为常规表达式。这是代码:

function isArray(obj) {
    return toString.call(obj) === "[object Array]";
}

function isObject(obj) {
    return Object.prototype.toString.call(obj) === '[object Object]'
}

var regexTest = /^\/(.*)\/([gimy]*)$/;

function convertRegex(item) {
    if (isArray(item)) {
        // iterate over array items
        for (var i = 0; i < item.length; i++) {
            item[i] = convertRegex(item[i]);
        }
    } else if (isObject(item)) {
        for (var prop in item) {
            if (item.hasOwnProperty(prop)) {
                item[prop] = convertRegex(item[prop]);
            }
        }
    } else if (typeof item === "string") {
        var match = item.match(regexTest);
        if (match) {
            item = new RegExp(match[1], match[2]);
        }
    }
    return item;
}

以及示例用法:

var result = convertRegex(testObj);

我在调试器中逐步执行的测试环境:http: //jsfiddle.net/jfriend00/bvpAX/

于 2013-10-27T00:25:24.030 回答
0

在有更好的解决方案之前,我将添加alert(等)到我的局部变量列表中,这将掩盖 eval 范围内的全局/内置函数:

var deteleGlobals =
    'var ' +
    Object.getOwnPropertyNames(window)
      .join(',')
      .replace(/(?:eval|chrome:[^,]*),/g, '') +
    ',alert,confirm,prompt,setTimeout;'
;

jsFiddle

于 2013-10-26T23:39:11.007 回答