Eval is evil... So what should I use instead?
Asked Answered
R

9

23

An ajax request returns me a standard JSON array filled with my user's inputs. The input has been sanitized, and using the eval() function, I can easily create my javascript object and update my page...

So here's the problem. No matter how hard I try to sanitize the inputs, I'd rather not use the eval() function. I've checked google for ways to use "JSON in AJAX without eval" and have ran accross a bunch of different methods...

Which one should I use? Is there a standard, proven-secure way of doing this?

Reuben answered 14/3, 2009 at 19:55 Comment(2)
Have a look at: #87013Yare
I thinks eval in this case isn't evil... Maybe you should take a look at that question: When is JavaScript’s eval() not evil?Devoirs
S
22

json.org has a nice javascript library

simple usage:

JSON.parse('[{"some":"json"}]');
JSON.stringify([{some:'json'}]);

Edit: As pointed out in comments, this uses eval if you look through its source (although it looks to be sanitized first)

to avoid it completely, look at json_parse or json-sans-eval

json2.js is insecure, json_parse.js is slow, json-sans-eval.js is non-validating

Sinclair answered 14/3, 2009 at 20:8 Comment(2)
It uses eval only as fallback for browsers that doesn't natively support the JSON object, and if this does not have the "parse" function.Cotyledon
json2.js is insecure from where is that ? it has 1mb of regex which syntisize the string before uses evalJamila
E
11

Is there a standard, proven-secure way of doing this?

There is a proposed standard way of doing this, in the forthcoming ECMAScript 3.1 version of JavaScript: JSON.parse.

It will be supported in IE8, Firefox 3.1/3.5 and most likely the other popular browsers in the future. In the meantime, you can fall back to, or use exclusively, eval(). Evil it may or may not be; certainly it will be slower than JSON.parse. But that's the usual way to parse JSON today.

If an attacker is able to inject malcious JavaScript into content you are spitting out via JSON, you have bigger problems to worry about than eval-is-evil.

Erinerina answered 14/3, 2009 at 20:9 Comment(1)
R
9

I would say, once the input is sanitized, eval is the best way to go. If your server gets compromised, people will be able to send whatever scripts they want to the client anyway. So putting an eval is not a big security risk. If you are worried about people manipulating the packets before they reach the client then, again, the scripts themselves can be modified.

Don't worry about eval. But make sure to wrap it in a try...catch block so your users don't get JS errors if your JSON gets mangled.

:)

Revenuer answered 14/3, 2009 at 19:58 Comment(0)
A
2

To safely convert JSON to a JS object you should use a JSON parser such as the JSON.parse() function provided by this library.

Arkwright answered 14/3, 2009 at 20:9 Comment(0)
L
0

Compare to the command design pattern: http://en.wikipedia.org/wiki/Command_pattern. Given this, you can precisely define the operations a client can execute and your application will be as safe as the underlying interpretation.

Laue answered 14/3, 2009 at 19:58 Comment(0)
K
0

Depends on what you're trying to accomplish with the sanitation. I've had great success w/the prototype framework's support for JSON and safe evaluation.

Kg answered 14/3, 2009 at 20:4 Comment(0)
S
0

If you're certain there's no injection risk, and you're not eval()ing in a loop, then use eval(). It will compare favorably to other options which will certainly be slower, might break, and will require the client to download additional code.

Shout answered 4/6, 2009 at 3:19 Comment(0)
M
0

"stolen" from jQuery

// Try to use the native JSON parser first
return window.JSON && window.JSON.parse ?
    window.JSON.parse( data ) :
    (new Function("return " + data))();
Moorefield answered 28/7, 2010 at 9:55 Comment(0)
M
0

Issue: The problem eval poses is that it executes in the global scope

eval.call(document, "console.log(this)")
eval.call(navigator, "console.log(this)")
eval.call(window, "console.log(this)")
(function(){eval.call(document, "console.log(this)")})()
>Window

Scenario:

Assume you are using individual attributes in the markup code of various document-elements such as an attribute onvisible

<img src="" onvisible="src='http://www.example.com/myimg.png';">

You would like to get all elements with this attribute, turn the onvisible-content-string into a closure and put it into an EventHandler queue. This is where the JS Function constructor comes into play.

Function === 0..constructor.constructor
>true

Function('return [this, arguments]').call(window, 1,2,3)
>Window, Arguments[3]]
Function('return [this, arguments]').call(document, 1,2,3)
>Document, Arguments[3]]
Function('return [this, arguments]').call(navigator, 1,2,3)
>Navigator, Arguments[3]]    

Putting it all together:

var eventQueue = [];
var els = document.querySelectorAll('[onvisible]');

for (var el in els) {
    var jscode = els[el].getAttribute('onvisible');
    eventQueue.push( {el:els[el], cb:Function(jscode)} )
}

//eventQueue[0].cb.call(scope, args);
Microsome answered 30/4, 2012 at 7:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.