59

I want an easy way to do a "calculator API" in Python.

Right now I don't care much about the exact set of features the calculator is going to support.

I want it to receive a string, say "1+1" and return a string with the result, in our case "2".

Is there a way to make eval safe for such a thing?

For a start I would do

env = {}
env["locals"]   = None
env["globals"]  = None
env["__name__"] = None
env["__file__"] = None
env["__builtins__"] = None

eval(users_str, env)

so that the caller cannot mess with my local variables (or see them).

But I am sure I am overseeing a lot here.

Are eval's security issues fixable or are there just too many tiny details to get it working right?

vaultah
  • 44,105
  • 12
  • 114
  • 143
flybywire
  • 261,858
  • 191
  • 397
  • 503

4 Answers4

76

are eval's security issues fixable or are there just too many tiny details to get it working right?

Definitely the latter -- a clever hacker will always manage to find a way around your precautions.

If you're satisfied with plain expressions using elementary-type literals only, use ast.literal_eval -- that's what it's for! For anything fancier, I recommend a parsing package, such as ply if you're familiar and comfortable with the classic lexx/yacc approach, or pyparsing for a possibly more Pythonic approach.

Alex Martelli
  • 854,459
  • 170
  • 1,222
  • 1,395
15

It is possible to get access to any class that has been defined in the process, and then you can instantiate it and invoke methods on it. It is possible to segfault the CPython interpreter, or make it quit. See this: Eval really is dangerous

Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
1

Perl has a Safe eval module http://perldoc.perl.org/Safe.html

Googling "Python equivalent of Perl Safe" finds http://docs.python.org/2/library/rexec.html

but this Python "restricted exec" is deprecated.

--

overall, "eval" security, in any language, is a big issue. SQL injection attacks are just an example of such a security hole. Perl Safe has had security bugs over the years - most recent one I remember, it was safe, except for destructors on objects returned from the safe eval.

It's the sort of thing that i might use for my own tools, but not web exposed.

However, I hope that someday fully secure evals will be available in many / any languages.

Dirk Bester
  • 1,791
  • 19
  • 21
Krazy Glew
  • 7,210
  • 2
  • 49
  • 62
1

The security issues are not (even close to) fixable.

I would use pyparsing to parse the expression into a list of tokens (this should not be too difficult, because the grammar is straightforward) and then handle the tokens individually.

You could also use the ast module to build a Python AST (since you are using valid Python syntax), but this may be open to subtle security holes.

Katriel
  • 120,462
  • 19
  • 136
  • 170
  • I think this doesn't work, because I set locals and globals to None so they are not visible from inside the eval expression. – flybywire Aug 18 '10 at 14:51
  • @flybywire: apologies, that is true; edited. Still a bad idea though. – Katriel Aug 18 '10 at 14:52
  • @flybywire: http://stackoverflow.com/questions/661084/security-of-pythons-eval-on-untrusted-strings – Katriel Aug 18 '10 at 14:56
  • @katrielalex can you please list the issues you see with the eval's security. I found this http://stackoverflow.com/questions/661084/security-of-pythons-eval-on-untrusted-strings on SO and @jerub provides a link to the problems with eval. Apart from that, are there any other issues that one needs to be aware of? – Gangadhar Aug 18 '10 at 14:58
  • 12
    @Ganga, have you thought for example about how `(1).__class__.__bases__[0].__subclasses__()` gives you **every** class existing in your system? Just for starters... – Alex Martelli Aug 18 '10 at 15:04
  • @Gangadhar: Off the top of my head, you can raise an error from e.g. `users_str = "[[]]*8**50"`. I'll see if I can find another way around -- but even if I can't, there's no guarantee *nobody* can. – Katriel Aug 18 '10 at 15:05
  • it is possible to crash python interpreter with `ast.literal_eval` – Antti Haapala -- Слава Україні Jul 26 '17 at 08:24