In my web app, I would like to accept arbitrary JavaScript objects as GET parameters. So I need to parse location.search
in a way similar to eval
, but I want to create self-contained objects only (object literals, arrays, regexps and possibly restricted-access functions):
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);
I came up with a version of saferEval
function that blocks access to global variables, but it does not block access to built-in functions like 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;
};
};
See my jsFiddle - alert(1)
code is executed. Note that top.location
is not accessible to jsFiddle scripts, you have to run the code locally if you want to fiddle with actual query parameters like ?filter={a: /%5Cd+/g}
.
I would use JSON , but I need to have regular expressions at arbitrary places inside arrays and objects. I do not send any of these object back to the server, so using eval
for this shouldn't harm the security so much...
How can I convert a string (that encodes JavaScript object) into object without giving it access to global namespace and built-in functions?
UPDATE - only useful "arbitrary" objects turned out to be regexp literals...
Per your comment that you'd be interested in seeing a solution that just solves the issue of having regex values in your JSON, then you could encode all regex values as strings in normal JSON like this:
"/this is my regex/"
Then, process the JSON normally into a javascript object and then call this function on it which will recursively walk through all objects and arrays, find all items that are strings, check them for the above format and, if found, convert those items to regular expressions. Here's the code:
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;
}
And a sample usage:
var result = convertRegex(testObj);
Test environment that I stepped through the execution in the debugger: http://jsfiddle.net/jfriend00/bvpAX/
Until there is better solution, I will add alert
(and the like) into my list of local variables which would overshadow global/built-in functions within the eval scope:
var deteleGlobals =
'var ' +
Object.getOwnPropertyNames(window)
.join(',')
.replace(/(?:eval|chrome:[^,]*),/g, '') +
',alert,confirm,prompt,setTimeout;'
;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.