Is It Evil to Use Eval to Convert a String to a Function

When is JavaScript's eval() not evil?

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.

Why is using the JavaScript eval function a bad idea?

  1. Improper use of eval opens up your
    code for injection attacks

  2. Debugging can be more challenging
    (no line numbers, etc.)

  3. eval'd code executes slower (no opportunity to compile/cache eval'd code)

Edit: As @Jeff Walden points out in comments, #3 is less true today than it was in 2008. However, while some caching of compiled scripts may happen this will only be limited to scripts that are eval'd repeated with no modification. A more likely scenario is that you are eval'ing scripts that have undergone slight modification each time and as such could not be cached. Let's just say that SOME eval'd code executes more slowly.

what does eval do and why its evil?

eval() takes the string it is given, and runs it as if it were plain JavaScript code.

It is considered "evil" because:

  • It over-complicates things - Most cases where eval() is used, there would be a much simpler solution that didn't require it. This example in the question is a perfect case in point: there is absolutely no need for eval() for an expression like this. JS has perfectly good syntax for referencing an object property name as a string (myObject["x"] is the same as myObject.x).

  • It's much harder to debug - It's harder to work with it in a debugger, and even once you have managed to work out what's going on, you have you extra work to do because you have to debug both the eval'd code, and the code that generated the original string to eval.

  • It slows things down - The script compiler cannot pre-compile code in an eval(), because it doesn't know what the code will contain until it gets there. So you lose out on a some of the performance benefits in modern Javascript engines.

  • It is a hacker's dream - eval() runs a string as code. Hackers love this because it's much easier to inject a string into a program than to inject code; but eval() means you can inject a string, and get it to run as code. So eval() makes your code easier to hack. (this is less of an issue for browser-based Javascript than other languages, as JS code is accessible in the browser anyway, so your security model should not be based on your code being immutable, but nevertheless, injection hacks can still be a problem, particularly with cross-site attacks).

Why is using 'eval' a bad practice?

Yes, using eval is a bad practice. Just to name a few reasons:

  1. There is almost always a better way to do it
  2. Very dangerous and insecure
  3. Makes debugging difficult
  4. Slow

In your case you can use setattr instead:

class Song:
"""The class to store the details of each song"""
attsToStore=('Name', 'Artist', 'Album', 'Genre', 'Location')
def __init__(self):
for att in self.attsToStore:
setattr(self, att.lower(), None)
def setDetail(self, key, val):
if key in self.attsToStore:
setattr(self, key.lower(), val)

There are some cases where you have to use eval or exec. But they are rare. Using eval in your case is a bad practice for sure. I'm emphasizing on bad practice because eval and exec are frequently used in the wrong place.

Replying to the comments:

It looks like some disagree that eval is 'very dangerous and insecure' in the OP case. That might be true for this specific case but not in general. The question was general and the reasons I listed are true for the general case as well.

About eval is evil and consenting adults

eval is evil because user input gets into it at some point. You don’t (well, shouldn’t) have to be worried about code pretending to not delete all files, because code can do that anyways – tada:

def foo(duck):
duck.quack()

class EvilDuck(object):
os.system('rm -rf /')

def quack(self):
pass

And rm -rf / has a good chance of not working, too. ;)

Basically, “consenting adults” is “trust your code”. eval is “trust all code”. Depending on where you get that code, eval can be fine, but it’s unnecessary 99% of the time, and it can also be hard to guarantee as secure.

When (if ever) is eval NOT evil?

Eric Lippert sums eval up over three blog posts. It's a very interesting read.

As far as I'm aware, the following are some of the only reasons eval is used.

For example, when you are building up complex mathematical expressions based on user input, or when you are serializing object state to a string so that it can be stored or transmitted, and reconstituted later.

Calculate string value in javascript, not using eval

This is exactly the place where you should be using eval(), or you will have to loop through the string and generate the numbers. You will have to use the Number.isNaN() method to do it.

Eval is evil... So what should I use instead?

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

Are eval() and new Function() the same thing?

No, they are not the same.

  • eval() evaluates a string as a JavaScript expression within the current execution scope and can access local variables.
  • new Function() parses the JavaScript code stored in a string into a function object, which can then be called. It cannot access local variables because the code runs in a separate scope.

Consider this code:

function test1() {
var a = 11;
eval('(a = 22)');
alert(a); // alerts 22
}

If new Function('return (a = 22);')() were used, the local variable a would retain its value. Nevertheless, some JavaScript programmers such as Douglas Crockford believe that neither should be used unless absolutely necessary, and evaling/using the Function constructor on untrusted data is insecure and unwise.



Related Topics



Leave a reply



Submit