views:

6091

answers:

17

I'm writing some JavaScript to parse user-entered functions (for spreadsheet-like functionality). Having parsed the formula I could convert it into JavaScript and run eval() on it to yield the result. However, I've always shied away from using eval() if I can avoid it because it's evil (and, rightly or wrongly, I've always thought it is even more evil in JavaScript because the code to be evaluated might be changed by the user).

Obviously one has to use eval() to parse JSON (I presume that JS libraries use eval() for this somewhere, even if they run the JSON through a regex check first), but when else, other than when manipulating JSON, it is OK to use eval()?

+6  A: 

The first JavaScript JSON parser I found doesn't use eval.

David Dorward
+17  A: 

When you trust the source.

In case of JSON, it is more or less hard to tamper with the source, because it comes from a web server you control. As long as the JSON itself contains no data a user has uploaded, there is no major drawback to use eval.

In all other cases I would go great lengths to ensure user supplied data conforms to my rules before feeding it to eval().

Tomalak
A json string should always be tested against the json grammar before using it in eval(). So the json string "{foo:alert('XSS')}" would not pass since “alert('XSS')” is not a proper value.
Gumbo
Or when the environment is secure.
Eli Grey
But can you ever really trust the source when you're using a protocol that is susceptible to man-in-the-middle attacks?
Justin Johnson
Well, use HTTPS, then. OTOH: man-in-the-middle is not the typical attack scenario for the garden variety web app, whereas i.e. cross-site-scripting is.
Tomalak
A: 

The only instance when you should be using eval() is when you need to run dynamic JS on the fly. I'm talking about JS that you download asynchronously from the server...

...And 9 times of 10 you could easily avoid doing that by refactoring.

Oli
A: 

It's okay to use it if you have complete control over the code that's passed to the eval function.

John Topley
+7  A: 

I tend to follow Crockford's advice for eval(), and avoid it altogether. Even ways that appear to require it do not. For example, the setTimeout() allows you to pass a function rather than eval.

setTimeout(function() {
  alert('hi');
}, 1000);

Even if it's a trusted source, I don't use it, because the code returned by JSON might be garbled, which could at best do something wonky, at worst, expose something bad.

swilliams
How would a successful call to a web server yield a garbled result (bugs in the JSON-generating web server code notwithstanding)?
Tomalak
I think that bugs in the JSON formatter on the server side are certainly an issue. Does the response from the server depend on any kind of user submitted text? Then you gotta watch for XSS.
swilliams
If your webserver isn't authenticated via HTTPS, then you could suffer some sort of man-in-the-middle attack where another host intercepts the request and sends its own data.
Ben Combee
If someone can perform man-in-the-middle attack, he can easily inject anything to your scripts.
el.pescado
You should not rely on your javascript code at all... You not rely on anything that runs on the client side... If someone does man-in-the-middle attack why would he mess with your json objects? He can serve a different webpage to you and different js files...
Calmarius
A: 

Only during testing, if possible. Also note that eval() is much slower than other specialized JSON etc. evaluators.

Eric Wendelin
+11  A: 

eval() isn't evil. Or, if it is, it's evil in the same way that reflection, file/network IO, threading, and IPC are "evil" in other languages.

If, for your purpose, eval() is faster than manual interpretation, or makes your code simpler, or more clear... then you should use it. If neither, then you shouldn't. Simple as that.

Shog9
A: 

There is no reason not to use eval() as long as you can be sure that the source of the code comes from you or the actual user. Even though he can manipulate what gets sent into the eval() function, thats not a security problem because he is able to manipulate the source code of the web site and could therefore change the javascript code itself.

So... when not use eval()? Eval() should only not be used when there is a chance that a third party could change it. Like intercepting the connection between the client and your server (but if that is a problem use HTTPS). You shouldn't eval() for parsing code that is written by others like in a forum.

Georg
+31  A: 

I'd like to take a moment to address the premise of your question - that eval() is "evil". The word "evil", as used by programming language people, usually means "dangerous", or more precisely "able to cause lots of harm with a simple-looking command". So, when is it OK to use something dangerous? When you know what the danger is, and when you're taking the appropriate precautions.

To the point, let's look at the dangers in the use of eval(). There are probably many small hidden dangers just like everything else, but the two big risks - the reason why eval() is considered evil - are performance and code injection.

  • Performance - eval() runs the interpreter/compiler. If your code is compiled, then this is a big hit, because you need to call a possibly-heavy compiler in the middle of run-time. However, JavaScript is still mostly an interpreted language, which means that calling eval() is not a big performance hit in the general case (but see my specific remarks below).
  • Code injection - eval() potentially runs a string of code under elevated privileges. For example, a program running as administrator/root would never want to eval() user input, because that input could potentially be "rm -rf /etc/important-file" or worse. Again, JavaScript in a browser doesn't have that problem, because the program is running in the user's own account anyway. Server-side JavaScript could have that problem.

On to your specific case. From what I understand, you're generating the strings yourself, so assuming you're careful not to allow a string like "rm -rf something-important" to be generated, there's no code injection risk (but please remember, it's very very hard to ensure this in the general case). Also, if you're running in the browser then code injection is a pretty minor risk, I believe.

As for performance, you'll have to weight that against ease of coding. It is my opinion that if you're parsing the formula, you might as well compute the result during the parse rather than run another parser (the one inside eval()). But it may be easier to code using eval(), and the performance hit will probably be unnoticeable. It looks like eval() in this case is no more evil than any other function that could possibly save you some time.

You're not addressing the issue of code that uses eval being difficult to debug
bobobobo
There is a more complete answer to this question here http://stackoverflow.com/questions/951373/when-is-eval-evil-in-php
bobobobo
Code Injection is a very serious issue for javascript if you are at all concerned about your user's data. Injected code will run (in the browser) as if it came from your site, letting it do any sort of shenanigan that the user could do manually. If you allow (third-party) code to enter you page, it can order things on behalf of your customer, or change their gravatar, or whatever they could do through your site. Be very careful. Letting hackers own your customers is just as bad as letting them own your server.
Sean McMillan
If the data is comming from your server and its something that you, the developer has generated, there is no harm in using eval(). The real harm is beliving everything you read. You see lots of people saying eval() is evil and they have no idea why except that they read it somewhere.
Sir Psycho
@Sean McMillan: I want to believe you, but if someone is going to intercept and change javascript going to `eval()` from your server, they could also just change the page's source in the first place, and also take control of the user's information . . . I don't see the difference.
Walt W
Sir Psycho - I wish I could give you ten upvotes
plodder
A: 

I just want to add my 0.50$ here, I saw people advocate to not use eval, because is evil but saw the same people use dinamically Function and setTimeout, so they use eval under the hoods :D btw, if your sandbox is not sure enought (eg. if you're working on a site that allow code injection) eval is the last of your problems, the basic rule of security is that all input is evil, but in case of javascript even javascript itself could be evil, because in javascript you can overwrite any function and you just can't be sure you're using the real one, so, if a malicious code start before you, you can't trust any javascript built-in function :D

Now the epilogue to this post is: if you REALLY need it (80% of the time eval is NOT needed) and you're sure of what you' re doing, just use eval (or better Function ;) ), closures and OOP cover the 80/90% of the case where eval can be replaced using another kind of logic, the rest is dinamically generated code (for example if you' re writing an interpreter) and as you already said evaluating json (here you can use the crockford safe evaluation ;) )

kentaromiura
+2  A: 

Only if the parameter you pass it is "alert('No!')"...

JoeBloggs
A: 

If i's really needed eval is not evil. But 99.9% of the uses of eval that I stumble across are not needed (not including setTimeout stuff).

For me the evil is not a performance or even a security issue (well, indirectly it's both). All such unnecessary uses of eval add to a maintenance hell. Refactoring tools are thrown off. Searching for code is hard. Unanticipated effects of those evals are legion.

PEZ
eval isn't necessary for setTimeout. You can use a function reference there too.
Matthew Crumley
+1  A: 

My believe is that eval is a very powerfull function for client side web application and safe... As safe as javascript, which are not. :-) The secutity issues are essentially a server side problem because, now, with tool like firebug, you can attack any javasript application.

A: 

Microsoft explains why eval() is slow in their browser on IE Blog

A: 

eval is rarely the right choice. While there may be numerous instances where you can accomplish what you need to accomplish by concatenating a script together and running it on the fly, you typically have much more powerful and maintainable techniques at your disposal: associative-array notation (obj["prop"] is the same as obj.prop), closures, object-oriented techniques, functional techniques - use them instead.

Justice
+2  A: 

As far as client script goes, I think the issue of security is a moot point. Everything loaded into the browser is subject to manipulation and should be treated as such. There is zero risk in using an eval() statement when there are much easier ways to execute javascript and/or manipulate objects in the DOM, such as the URL bar in your browser.

javascript:alert("hello");

If someone wants to manipulate their DOM, I say swing away. Security to prevent any type of attack should always be the responsibility of the server application, period.

From a pragmatic standpoint, there's no benefit to using an eval() in a situation where things can be done otherwise. However, there are specific cases where an eval SHOULD be used. When so, it can definitely be done without any risk of blowing up the page.

<html>
<body>

<textarea id="output"></textarea><br/>
<input type="text" id="input" />
<button id="button" onclick="execute()">eval</button>

<script type="text/javascript">
var execute = function(){
    var inputEl = document.getElementById('input');
    var toEval = inputEl.value;
    var outputEl = document.getElementById('output');
    var output = "";

    try {
     output = eval(toEval);
    }
    catch(err){
     for(var key in err){
      output += key + ": " + err[key] + "\r\n";
     }
    }
    outputEl.value = output;
}
</script>

<body>
</html>
+3  A: 

Lets get real folks:

  1. Every major browser now has a built in console which your would-be hacker can use with abandon to invoke any function with any value - why would they bother to use an eval statement - even if they could?

  2. If it takes 0.2s to compile 2000 lines of javascript what is my performance degradation if I eval 4 lines of JSON?

Even Crockford's explanation for 'eval is evil' is weak.

"eval is Evil
The eval function is the most misused feature of JavaScript. Avoid it"

As Crockford himself might say "This kind of statement tends to generate irrational neurosis. Don't buy it"

Understanding eval and knowing when it might be useful is way more important. For example eval is a sensible tool for evaluating server responses that were generated by your software.

BTW: Prototype.js calls eval directly 5 times (including in evalJSON() and evalResponse()). JQuery uses it in parseJSON (via Function constructor)

plodder