safe eval of moderately simple math expressions

Matt Nordhoff mnordhoff at mattnordhoff.com
Thu Apr 9 18:25:51 CEST 2009


Joel Hedlund wrote:
> Hi all!
> 
> I'm writing a program that presents a lot of numbers to the user, and I
> want to let the user apply moderately simple arithmentics to these
> numbers. One possibility that comes to mind is to use the eval function,
> but since that sends up all kinds of warning flags in my head, I thought
> I'd put my idea out here first so you guys can tell me if I'm insane. :-)
> 
> This is the gist of it:
> ----------------------------------------------------------
> import math
> 
> globals = dict((s, getattr(math, s)) for s in dir(math) if '_' not in s)
> globals.update(__builtins__=None, divmod=divmod, round=round)
> 
> def calc(expr, x):
>     if '_' in expr:
>         raise ValueError("expr must not contain '_' characters")
>     try:
>         return eval(expr, globals, dict(x=x))
>     except:
>         raise ValueError("bad expr or x")
> 
> print calc('cos(x*pi)', 1.33)
> ----------------------------------------------------------
> 
> This lets the user do stuff like "exp(-0.01*x)" or "round(100*x)" but
> prevents malevolent stuff like "__import__('os').system('del *.*')" or
> "(t for t in (42).__class__.__base__.__subclasses__() if t.__name__ ==
> 'file').next()" from messing things up.
> 
> I assume there's lots of nasty and absolutely lethal stuff that I've
> missed, and I kindly request you show me the error of my ways.
> 
> Thank you for your time!
> /Joel Hedlund

I'm way too dumb and lazy to provide a working example, but someone
could work around the _ restriction by obfuscating them a bit, like this:

>>> '\x5f'
'_'
>>> getattr(42, '\x5f\x5fclass\x5f\x5f') # __class__
<type 'int'>

Is that enough to show you the error of your ways? :-D Cuz seriously,
it's a bad idea.

I'm sorry, but I don't know a good solution. The simplicity of eval is
definitely very attractive, but it's just not safe.

(BTW: What if a user tries to do some ridiculously large calculation to
DoS the app? Is that a problem?)
-- 



More information about the Python-list mailing list