Here is the problem string:
$.ajax(......
,success:function(msg){
var obj = eval('['+msg.d+']');
},
....
}
msg.d contains something like:
new Person(2, 'Name Surname','This is just string came from Par'is at Sat'urday');
How can pass the javascript problem ?
If the string really is as you've quoted it, it has a syntax error and will not work (it has an errant ' inside the word "Saturday"). Otherwise, though, change the brackets ([ and ]) in your eval call to parentheses (( and )):
var obj = eval('('+msg.d+')');
However, it should almost never actually be necessary to do this (or indeed to use eval at all). It's almost always possible, and desirable, to refactor slightly and avoid it.
If that's a literal quote from your code, see also dvhh's answer below, your function argument name (msg.d) is invalid.
Using eval in this scenario is actual quite dangerous. You really ought to be using XML or JSON. (That's why they call it AJAX.)
the function argument should be a valid javascript identifier
try changing msg.d to msg_d for example
You may need to escape your string, because this example works fine:
function MyObject(myvar){
this.hello = function(){
alert('myvar= ' + myvar);
};
}
var obj1 = new MyObject('hello');
obj1.hello();
var obj2 = eval("new MyObject('world')");
obj2.hello();
(Edit: By the way, I assume msg.d is a typo due to editing the snipplet before posting on StackOverflow ?)
I would avoid using eval() for security reasons. If a user can get malicious code into the database, there's a chance it could end up in this eval expression, wreaking havoc for anybody who visits this page.
Instead of using eval, I'd recommending returning JSON from the AJAX request. You can then easily parse the values and build a new Person object with that data.
Related
I have a json data that has unknown objects like this:
var x = {
"unknown1": 234,
"unknown2": 324
}
I can get the properties name as:
var prop1 = Object.keys(x)[0];
Now I want to find the value of this property. I can obviously do x[prop1], but I wanted to do x.prop1. My question is:
What are ways to convert prop1 into an expression so that I could use x.prop1?
If eval can solve this then how and why would eval create security problems in this case?
What are ways to convert prop1 into an expression so that I could use x.prop1?
You can't, without generating source code and compiling/evaluating it.
If eval can solve this then how and why would eval create security problems in this case?
Yes, eval (and its close cousin new Function) can do this. It's only a security issue if what you're evaling comes from an untrusted source. If you can trust that the value of prop1 doesn't contain malicious content, then you can use eval("x." + prop1) to do this. Or new Function("x", "return x." + prop1)(x).
But there's no good reason to. Just use x[prop1]. That's what brackets notation is for. It's normal practice, it doesn't have to fire up a parser and code generator, it's faster, and you don't have to worry about prop1 having malicious code in it. If you use eval or new Function, it's not normal practice, it has to fire up a parser and code generator, it's slower, and you have that niggling concern in the back of your mind. So use x[prop1]. :-)
As #mhodges says in his comment you could add a new property.
but it might seem redundant to do so.
x.prop1 = x[Object.keys(x)[0]]
I have a text input.
I want the user to be able to fill out a value in that text input like some of these examples:
results[0].address_components[0].long_name
results[0].formatted_address
fo.o[0].bar (where fo.o is a single key)
etc. (pretty much literally anything)
Then I want to take that value and use it as a key on some parsed JSON. So like...
$.parseJSON('data.json').results[0].address_components[0].long_name would return something like San Francisco.
How can I do this?
If I save the input value as a variable, say selector, and then try $.parseJSON('data.json')[selector] it just comes back undefined.
If I try to regex the selector and convert all instances of [ into . and remove all ] and split at . then reduce, then selectors like fo.o (one key) will break...
Thanks in advance!
You should generally set the results of parseJSON to a variable, rather than parse it every time you access it. parseJSON is generally going to go down to C code (depending on the environment), but it will still be really inefficient to call it over and over.
var res = $.parseJSON('data.json');
From there, you can access it like you would any other JavaScript object:
res.results, which is identical to res["results"] (which, in your case appears to be some kind of array).
A string key with special characters (., -, and pretty much anything non a-zA-Z0-9) is always accessed via the second form: res["fo.o"].
Note that this chains, so you can access res["fo.o"]["bar"] exactly as you'd address res["fo.o"].bar.
I would recommend using a JavaScript library like lodash for this (if this is feasible in your project, otherwise looking at its implementation might help):
It provides a large set of utility functions. The get function does exactly what you are looking for, namely it resolves a path on an object.
Sample code (assuming _ is your lodash reference):
var path = 'results[0].address_components[0].long_name'; // the user input
var data = $.parse('data.json');
var result = _.get(data, path); // resolves the path on the data object
As for the fo.o property name, I doubt there would be an easy solution, as this essentially makes your syntax ambiguous. How would you distinguish between a property fo.o and fo?
use eval. You would put everything as a string. So just concatenate strings based on the input. Then eval it. for example:
var str = "$.parseJSON('data.json').results[0].address_components[0].long_name";
and then eval it at runtime.
var result = eval(str);
I have a website that returns a JSON-like data structure like this:
{
"name":"tom jones",
"no": 123,
"storedproc": function(){
callbuyer(0123);
}
}
I'm getting this data using $.ajax() with dataType "JSON". Unfortunately, my $.ajax() calls the error callback because my data contains a function().
How can I parse this correctly? I really need to store the function in a variable and call it later.
That is simply not legal JSON (as you know given the title of the question) See the offical JSON syntax. The nice thing about real JSON is that one can use JSON.parse which safely wraps an eval call.
While eval could be used, I would suggest revisiting the architecture of your application and find some other way to do what you are trying to do.
In particular, I would have the server return the 0123 only, and let your client keep the logic that lets it know, in certain cases, which functions apply (in the scenario here, the function would be callbuyer).
This should work because you say you want to call the function which is the value of the storedproc later. Since the body of this function contains a call to callbuyer it follows that your client side script knows what callbuyer is. The trick is for your server not to send back arbitrary, unconstrained functions, but rather data that your client can exploit somehow using the knowledge it has about the overall application.
Could you arrange to have the server return JSON like this:
{"name":"tom jones",
"no": 123,
"storeprocFn": callbuyer,
"arg": "0123"};
Then your callback function can call the callbuyer function and pass arg
Use eval to interpret the string as a javascript object. You won't be able to use the JSON data type though. I believe what you need to do is use 'text' as the dataType for the $.ajax call. Then do something like:
var data = eval('(' + text + ')');
Should work. Of course, eval is evil. But it would solve your problem. As long as you can guarantee there isn't anything malicious in the text (no unsanitized, user entered data) then you should be ok.
AFAIK, functions are left out when using JSON.stringify, it's just not meant to be used to clone full objects (props and methods). However, you might be able to pass the function body as a string.Say you decide on a string format like func=>var foo = 'bar'; return foo;. This should be passed as a regular JSON string, after parsing the object you could then iterate all properties, and convert those strings to functions like so:
for (var prop in parsedObj)
{
if (parsedObj.hasOwnProperty(prop) && parsedObj[prop].match(/^func\=\>/))
{
parsedObj[prop] = new Function(parsedObj[prop].replace('func=>',''));
}
}
Though, seriously, I'd say you might want to rethink your approach, this is not what JSON is for. It's unsafe, all JSON strings are eval'ed, after having made sure they contain no harmful code. This approach is creating a loophole/vulnerability that the JSON people worked hard for to seal off.
For your example will this work:
'user.storeproc = function() { callbuyer( user.no);};'
The Var 'user' is the object of the parsed json.
Ps: maybe you have to format user.no, from 123 to 0123
Following JSON extension, "JFON", does transport of functions and array-properties.
JFON uses eval and is intended for case if:
1) your data is from trusted source ( like not-derived from user input or is a code from your own server), and
2) you know there are no undesired side effects with context of "eval"
(it is a context of eval in function "fromJFON", line 127 )
3) it is costly to refactor your app to use "functionless" JSON;
4) JFON is one-day work, so may be needs more testing;
The idea: use selected property name to escape functions and arrays like
in strings when selected character "\" is used to pass \n and \ for itself.
In JFON, name "wrap" is selected to pass functions and itself: "wrap" : { "fun" : ... and "wrap" : { "esc" : ...
demo: http://landkey.org/Sandbox/z/spaceen86/js/btb/tests/jfon.htm
code ( use commit 0.0.86 ):
https://github.com/lancelab/spaceen/blob/master/js/btb/JFON.js
test: github.com/lancelab/spaceen/blob/master/js/btb/tests/jfon.htm
Here is another, "JWON" extension: JSON-comments, here-documents, monkey-patching of JSONs:
github.com/lancelab/Boardspirator/blob/master/diary/play/tp/jwon.js
I'm seeing code in the following form - is such use of eval() safe?
function genericTakeAction(frm_name,id,pagenum,action)
{
var rset=eval("document."+frm_name);
var x=eval("document."+frm_name+".edit_key");
var y=eval("document."+frm_name+".cAction")
if(x)
x.value=id;
if(y)
y.value=action;
page_list(pagenum);
}
Its used as:
<a href="javaScript:;" onClick="genericTakeAction('frmSearch',
'<?php echo $rec_id;?>','<?php echo $pagenum?>','makeOpen')"
class='link6'>Make Open</a>
Whether it's right or wrong, it's needlessly complicated.
function genericTakeAction(frm_name,id,pagenum,action)
{
var rset = document[frm_name];
var x = rset.edit_key;
var y = rset.cAction;
if(x)
x.value=id;
if(y)
y.value=action;
page_list(pagenum);
}
This works because in JavaScript, you can access an object's properties in one of two ways: Either using dotted syntax and a literal identifier, e.g. x = obj.foo;, or using bracket syntax and a string identifier, e.g. x = obj["foo"];. (Note how foo was not in quotes in the first one, but was in quotes for the second; but both do exactly the same thing. Also note that since the property name is a string in the second case, you can use any expression that results in a string, so y = "f"; x = obj[y + "oo"]; also works.)
P.S. It's wrong
eval() is generally frowned upon because, as you are already aware, it is considered unsafe.
In the browser environment, however, it is less of an issue, because in fact, any user could eval() any code they wanted to, using tools like Firebug, etc.
There is still an issue, in that the eval() embedded in the code can be run without the user knowing that he was triggering an eval(), but it's still much less of an issue than in a server-side environment like PHP.
eval() is actually typically used as you've shown to run JSON code being returned from a server-side request. Newer browsers can import JSON more safely using a dedicated JSON parse() function, but older browsers do not have this function and are forced to use eval() for this. Most JSON libraries have eval() in their code somewhere for this reason, but will generally do some sanitisation of the input before running it through eval().
Even if it might look a little bit convoluted, as others have already mentioned, from a pure security perspective, you have to make sure that the 'frm_name' parameter of the genericTakeAction() function can never contain user-supplied data.
In your example, the 'frm_name' parameter contains the hard-coded literal 'frmSearch'. So it is ok as long as this genericTakeAction() function does not get called somewhere else with user-supplied data for the 'frm_name' parameter.
See http://en.wikipedia.org/wiki/Cross-site_scripting#Traditional_versus_DOM-based_vulnerabilities
I'm using JSON to communicate some data through AJAX from the backend to the frontend (Javascript, of course). The XMLHttpRequest is done by a Prototypejs-written AJAX-handler (I'm still in the process of migrating to jQuery, but the noConflict-mode allows me to run both simultaneously), after which PHP sends the X-Json header with some data like objects = {'foo': 'bar'}.
The Prototypejs-Ajax.Request passes a json variable to the onSuccess-callback, containing all the JSONdata, so the processing isn't the hard part. However, I noticed that since the JSON is automatically evaluated, the objects variable is made global (and thus a member of the window object.
I know it's not really a problem since it's just an unused variable, but I always tried to stay away from global variables as much as possible. Additionally, the datasets may be pretty large on some occasions, so it'll just be a huge duplicate variable of which one is never used. So, if possible, I'd rather lose the global.
My question: how? If there's a good reason for this happening, or if this is just a Prototypejs-specific issue, or if this just indicates I'm doing something very wrong, please tell me :-)
Thanks!
Are you sending back objects = {"foo":"bar"} from PHP? When sending JSON, you just send {"foo":"bar"} and get the data as the return result of eval:
var json = '{"foo":"bar"}'; // This string would really be coming from PHP
// ...
var objects = eval('(' + json + ')'); // objects variable will be limited to the
// current scope.
If, for some reason, you must evaluate objects = ..., you can limit the variable to the current scope before running eval:
var objects;
eval('objects = {"foo":"bar"}');
Note that the PHP functions json_encode and json_decode will create "proper" JSON for you, which means it will use double quotes, and it will not use any kind of assignment (True JSON is limited to an array/object as the outer-most value, and it may not contain assignment or function calls. See the JSON specification.)
If the PHP is outputting objects = {'foo': 'bar'} then it isn't outputting JSON. JSON can't include the '=' character outside a string and uses the double quote character not the single quote. This means it is outputting JavaScript.
You have two options here.
The first is to try to restrict the scope of the JavaScript, the second is to fix the PHP so it outputs real JSON.
I would recommend the second option. Deal with JSON not JavaScript.
If you want to try to restrict it, then you need to limit the scope somehow. Possibly with:
function () {
eval("var " + php_generated_code);
doSomethingWith(object);
}
… although I'm not sure what the scope of eval() is.