在我的Web应用程序中,我想接受任意JavaScript对象作为GET参数。所以我需要以类似于eval
的方式解析location.search
,但我只想创建自包含的对象(对象文字、数组、正则表达式和可能的受限访问函数):
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.location
jsFiddle 脚本无法访问,但如果您想摆弄实际的查询参数(如 ?filter={a: /%5Cd+/g}
),则必须在本地运行代码。
我会使用 JSON,但我需要在数组和对象内的任意位置使用正则表达式。我不会将这些对象中的任何一个发送回服务器,因此为此使用 eval
应该不会对安全性造成太大损害......
如何将字符串(编码 JavaScript 对象)转换为对象而不授予其对全局命名空间和内置函数的访问权限?
更新 - 只有有用的"任意"对象原来是正则表达式文字......
根据您的评论,您有兴趣看到一个解决 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/
在有更好的解决方案之前,我将alert
(等)添加到我的局部变量列表中,这些变量会使评估范围内的全局/内置函数黯然失色:
var deteleGlobals =
'var ' +
Object.getOwnPropertyNames(window)
.join(',')
.replace(/(?:eval|chrome:[^,]*),/g, '') +
',alert,confirm,prompt,setTimeout;'
;
js小提琴