tags:

views:

75

answers:

2

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. Please help: are eval's security issues fixable or are there just too many tiny details to get it working right?

+1  A: 

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.

katrielalex
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
@flybywire: apologies, that is true; edited. Still a bad idea though.
katrielalex
@flybywire: http://stackoverflow.com/questions/661084/security-of-pythons-eval-on-untrusted-strings
katrielalex
@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
@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
@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.
katrielalex
+3  A: 

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