0

In JavaScript, eval is considered to be a bad idea mainly because it opens up your code to injection attacks. To quote this comment:

The attacks we are trying to avoid are when user provided values get saved, then later placed into javascript and eval'd. For example, I might set my username to: badHackerGuy'); doMaliciousThings(); and if you take my username, concat it into some script and eval it in other people's browsers then I can run any javascript I want on their machines (e.g. force them to +1 my posts, post their data to my server, etc.)

But why is this problem limited to JavaScript? Yes, JavaScript is the only language that runs on browsers, but there are contexts other than browsers where you want to avoid injection attacks.

(This part is tangential to my actual question, but people talk about the extreme, awesome power of metaprogramming. eval allows you to do metaprogramming and it sounds like the injection attack issue is the only big downside. Why is considered to be clear that the downside outweighs the upside?)

Adam Zerner
  • 17,797
  • 15
  • 90
  • 156
  • 1
    It *can* be done safely in JS, it's just rarely useful given problems that JS programmers usually face, which rarely involves metaprogramming for which `eval` would be helpful. Parsing scripts isn't uncommon, but that's done with lexers like Acorn, not with `eval`. – CertainPerformance Mar 12 '23 at 05:20
  • @CertainPerformance I'm not clear on exactly what your claim is. 1) That metaprogramming is rarely useful for JS programmers? 2) That using `eval` for metaprogramming is rarely useful? – Adam Zerner Mar 12 '23 at 05:28
  • I agree with both, though 2 especially – CertainPerformance Mar 12 '23 at 05:36
  • @CertainPerformance I see. So is this an accurate paraphrase? For the problems that JS programmers usually face, metaprogramming is rarely useful, `eval` especially, and so cost of potentially letting a security vulnerability slip in there usually outweighs the benefit of the power that metaprogramming would bring. – Adam Zerner Mar 12 '23 at 05:39
  • 1
    It's not so much the security vulnerability (sandboxing is possible, and running unread code unfortunately common) - it's that `eval` *just plain isn't that useful of a tool* usually, outside of calculating math and X/Y problems. If you find a situation where it really is [the best alternative](https://stackoverflow.com/questions/41191338/why-does-webpack-2-bundle-use-eval-to-wrap-code) among your choices, go for it, but such situations are rare. – CertainPerformance Mar 12 '23 at 05:47
  • @CertainPerformance Ah, I see. Thanks for clarifying. That makes sense. Sounds like a simplest tool for the job type of thing. – Adam Zerner Mar 12 '23 at 05:48
  • You don't need EVAL to do meta-programming. EVAL is useful to execute source code, but that is orthogonal to meta-programming. – Rainer Joswig Mar 12 '23 at 09:20

1 Answers1

3

I can only speak for Lisp but the answer is that your assumption is false: eval is, almost always, an extremely bad idea in Lisp code.

If you see (eval x) in a piece of code then unless you have detailed knowledge of what x is, you have no idea what this does: it can do anything (almost) that the Lisp system can do. If x contains, or may contain, untrusted data, then that's just a really, really bad idea for very obvious reasons.

You could make this safe by writing some kind of walker which looks at x and checks it is safe. But ... that walker is within epsilon of being an evaluator for your safe subset of Lisp: just use it, instead!

eval has uses in Lisp, so it is good that it is in the language, but the cases where you need it are few and far between: there are cases where you wish to be able to evaluate arbitrary Lisp source code, such as writing a development environment, but they're very, very rare.

In particular do not conflate (in Lisp) eval with metaprogramming. In Lisp the traditional approach to metaprogramming (I say 'traditional' because Scheme is arguably not, quite, like this) is rooted in two ideas:

  1. the source code of the language is representable as a suitably low-commitment data structure in the language itself;
  2. You can write functions, called macros, which will map from instances of this source code representation to other instances.

There is much more to it than this of course, but note: this does not require eval.

ignis volens
  • 7,040
  • 2
  • 12
  • Ah I see. I was conflating `eval` with metaprogramming. – Adam Zerner Mar 13 '23 at 01:29
  • Ah, but suppose we know **mostly** what `x` is, except for some untrusted value `y` that we interpolate into a specific spot in the `x` structure. The Lisp `eval` can be perfectly safe. E.g. `y` ends up in an evaluated subxpression of `x` which looks like `(quote y)`. Not the JS/Bash/Whatever `eval`; we must first convert the value into text, then lexically process it and correctly escape it so that none of it will be executed, or screw up the syntax to perpetrate injection. – Kaz Mar 30 '23 at 02:55
  • Also, if I know that `y` is a character string object (because I read it as a line from a text stream, say). I can safely embed it into a Lisp code template that I control and be sure nothing goes wrong when it is `eval`-ed. Mostly `eval` is frowned up in Lisp programming because it's often an inefficient, hacky solution to something that can be done without `eval`. Newbie Lisp programmers sometimes run into the problem that the arguments they want to pass to a function are held in a list, and they discover `eval` before they discover `apply`. – Kaz Mar 30 '23 at 03:22
  • @Kaz: "here is this really rare case where, if you *really* understand what you are doing, `eval` is only inefficient and hacky, not unsafe". OK. – ignis volens Mar 30 '23 at 11:59