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...