safe eval of moderately simple math expressions
Matt Nordhoff
mnordhoff at mattnordhoff.com
Thu Apr 9 12:25:51 EDT 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