21

Every time that someone mentions eval(), everyone says that there are "security issues" with it, but nobody ever goes into detail about what they are. Most modern browsers seem to be able to debug eval() just as well as normal code, and people's claims of a performance decrease are dubious/browser dependent.

So, what are the issues, if any, associated with eval()? I haven't been able to come up with anything that could be exploited with eval() in JavaScript. (I do see issues with eval()'ing code on the server, but client-side eval() seems to be safe.)

  • Client-side eval is only safe if you know the contents being passed come from the client performing the execution. – S.C. Jul 15 '15 at 16:50
  • Also only if you know they were not modified between the time the client generated them and the time the browser executes them. – S.C. Jul 15 '15 at 17:08
  • 3
    @S.C. Modified by whom, on what basis? In general, it is impossible harden a program against the end-user messing with its state with a debugger. But if it was modified by adding something that came from somewhere other than the client then obviously that would mean the contents don't come from the client anymore. – Random832 Jul 15 '15 at 18:54
  • 1
    @Random832, you are correct in that a developer should always assume the presentation layer can be modified by the client. They can break their own session and you shouldn't have to care about that. In practice, even if a client is not in an isolated, sterile environment, there is very little that could make a dangerous change without the previous existence of another compromise on the client's side (plugin, MITM, cache, physical access, etc). In theory, if you are not actively securing against it it is possible. How you want to balance practice and theory is up to you and your organization. – S.C. Jul 15 '15 at 19:15
  • 1
    What research have you done? Reasons to be wary of eval are described in a number of places. "nobody ever goes into detail about what they are" - Citation needed. This is clearly false. Just do a search on "eval" on this site and you'll find a bunch of posts that provide various levels of detail about risks with eval. See, e.g., security.stackexchange.com/q/25642/971, security.stackexchange.com/q/30365/971, security.stackexchange.com/a/90764/971, security.stackexchange.com/q/23192/971, to list a few I came across immediately. – D.W. Jul 15 '15 at 22:02
29

eval() executes a string of characters as code. You use eval() precisely because the string contents are not known in advance, or even generated server-side; basically, you need eval() because the JavaScript itself will generate the string from data which is available only dynamically, in the client.

Thus, eval() makes sense in situations where the JavaScript code will generate code. This is not intrinsically evil, but it is hard to do securely. Programming languages are designed to allow a human being to write instructions that a computer understands; to that effect, any language is full of small quirks and special behaviours that are supposed to help the human programmer (e.g. the automatic adding of ';' at the end of some statements in JavaScript). This is all nice and dandy for "normal" programming; but when you generate code from another program, based on data which may be potentially hostile (e.g. string excerpt from other site users), then you have to, as the developer for the code generator, know about all these quirks, and prevent hostile data to exploit them in damaging ways.

In that sense, code generators (and thus eval()) incur the same conceptual issues as raw SQL and its consequence, SQL injection attacks. Assembling at runtime an SQL request from externally provided parameters can be done securely, but this requires minding an awful lot of details, so the usual advice is not to do that. This relates to the usual conundrum of security, i.e. that it is not testable: you can test whether some piece of code works properly on correct data, but not that it never works improperly on incorrect data. Similarly, using eval() securely is possible, but it is so hard in practice that it is discouraged.

All of this is said in all generality. In your specific context, eval() might be safe. However, it takes some effort to have a context safe for use of eval(), that actually needs eval().

  • 8
    Can you give a more specific example of how this would occur? I get that eval() executes a string, but I'd like to know what's uniquely problematic about it. A user can already run arbitrary JS through the console, and so I'm wondering what's different about the danger posed by eval(). – Stack Tracer Jul 15 '15 at 16:40
  • 4
    The difference is in where the eval contents comes from. If the string contents being passed to the eval call have the potential to be influenced in one way or another by a user or pulled from the database onto a page of more than just the one user who sourced those contents, you have a possibility for XSS. If you are just letting the user execute arbitrary JS within their own session, no harm done unless someone else can somehow influence the contents again. This is similar to dynamically generating javascript on the server side with unfiltered values sourced by user input. – S.C. Jul 15 '15 at 16:48
  • 2
    Close but not necessarily. Suppose you run a site that lets me create content other users can see. Further suppose it lets me choose from a set of custom UI transitions to go along with that content and after investigation I find that set actually correlates to function names used in an eval statement. If I can find a way to append arbitrary JS to the transition code being executed, you will end up with a persistent XSS attack vector because I'm able to cause arbitrary JS to execute in the browser of anyone who view that content. That vulnerability would not exist if you didn't use eval. – S.C. Jul 15 '15 at 17:03
  • 2
    Bottom line is you are going to cause unknown code to execute in the users browsers. You can do your best to ensure it is safe code or code only from an accepted set of sources or behaviors, but at the end of the day you are still dealing with the principle of being as sure as you can be that nothing bad will execute as opposed to knowing for certain you do not provide the ability to execute anything harmful. If your scenario is simple enough that you can be sure it is always safe, it is almost always simple enough that you don't really need eval() at all. – S.C. Jul 15 '15 at 17:07
  • 5
    Your question about "only available to administrators" is exactly where you need to change your thinking. Reflected XSS is used for this exact situation. I'm logged in as administrator to example.com. Someone sends me a link in an email like www.example.com?abc=some_malicious_javascript and like a fool I click it. If the abc parameter is vulnerable, then this attack will work. You must ensure your use of eval() is defended from this type of attack. – mcgyver5 Jul 15 '15 at 19:22
14

eval() is a possible vector for cross-site scripting.
Under normal circumstances, an attacker attempting XSS might want to get script <script></script> tags past whatever encoding, filters or firewalls might be in place. If eval() is there operating on user input, it eliminates the need for script tags.

Eval is present in many malicious scripts because it helps obfuscate code and / or sneak prohibited characters past filters. For this reason, eval() is often checked for in user input. So, when using eval() you are, potentially, providing the attacker one of their necessary tools. I'm robbing a bank and I know I don't have to sneak a gun past any metal detectors because there are a bunch in the umbrella stand inside the building.

  • 2
    How is this different from just using the developer console? If I have a page with a big textbox, and a button which allows you to eval() everything in that textbox, I don't see what's different about that. – Stack Tracer Jul 15 '15 at 16:34
  • The difference is in where the eval contents comes from. If the string contents being passed to the eval call have the potential to be influenced in one way or another by a user or pulled from the database onto a page of more than just the one user who sourced those contents, you have a possibility for XSS. If you are just letting the user execute arbitrary JS within their own session, no harm done unless someone else can somehow influence the contents again. – S.C. Jul 15 '15 at 16:47
  • 7
    @Stack Tracer the goal of XSS is to execute the script in someone else's browser, not my own. – mcgyver5 Jul 15 '15 at 16:49
  • 2
    Not true. Pleae read about reflected XSS before making pronouncements about "no longer a need for XSS": owasp.org/index.php/… – mcgyver5 Jul 15 '15 at 19:06
  • 1
    @StackTracer Suppose Mallory and Alice both use a website that displays all error messages at /error.php?error=This+is+the+error+message. If Mallory sends Alice to /error.php?error=<script>+myEvilFunction(document.cookie)+</script> through, e.g. a link in an email, and the server has not properly sanitised user input, a reflected XSS attack will occur where Alice's cookies will be captured by the injected Javascript. – waiwai933 Jul 16 '15 at 0:10
2

As explained by others, one can use eval to dynamically create code which makes it harder to understand the control flow of the program. But, I don't consider eval much more evil than all the other ways to generate code at run time, like document.write(...), object.innerHTML(...) and others. While these are mostly used to change the DOM of the program they are also used to insert new code (i.e. add a script statement to the code, or a new element with some onXXXX handler etc).

And while eval is often used in attacks (XSS, malvertisement...) to circumvent filters or hide the real purpose of the code it is often used in an obfuscated form there, i.e. code like z='ev'; z+='al'; v=window; v[z]("alert(1)"). This means you are not on the safe side if you simply try to filter code with explicit calls of eval, because either the call is obfuscated or "good" functions like innerHTML are used for bad purposes.

2

In addition to the great points made here, I would like to clarify: what you are essentially dealing with any time you use eval() is having to answer the following questions:

  • Is it worth securing?
  • How thoroughly can I secure it and is that level acceptable?
  • How confident can I be that it will stay secure over future evolutions of the codebase and development team?
  • How does the risk and amount of effort required by the above compare to the effort of constructing the code in such a way that execution of dynamically generated and possibly unknown code is not required?

If you have thought through these questions more completely than an attacker would and are still considering using eval(), go for it. You might find you grow tired of thinking that through over the course of your development career and start avoiding its usage simply on principle.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.