safe eval of moderately simple math expressions
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sat Apr 11 06:46:45 EDT 2009
On Sat, 11 Apr 2009 11:03:16 +0200, Joel Hedlund wrote:
> Peter Otten wrote:
>> But what you're planning to do seems more like
>>
>>>>> def is_it_safe(source):
>> ... return "_" not in source
>> ...
>>>>> source = "getattr(42, '\\x5f\\x5fclass\\x5f\\x5f')" if
>>>>> is_it_safe(source):
>> ... print eval(source)
>> ...
>> <type 'int'>
>
> Bah. You are completely right of course.
>
> Just as a thought experiment, would this do the trick?
>
> def is_it_safe(source):
> return "_" not in source and r'\' not in source
>
> I'm not asking because I'm hellbent on having eval in my app, but
> because it's always useful to see what hazards you don't know about.
Can we pass your test and still write to a file? Too easy.
>>> file('spam.txt', 'r') # prove that the file doesn't exist
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
IOError: [Errno 2] No such file or directory: 'spam.txt'
>>>
>>> source = "4+(file('spam.txt', 'w').write('spam spam spam') or 0)+5"
>>> if is_it_safe(source):
... print eval(source)
...
9
>>> file('spam.txt', 'r').read()
'spam spam spam'
Can we pass your test and import a module and grab its docstring?
>>> source = "getattr(eval(chr(90+5)*2+'im'+'por'+'t'+chr(None or 95)*2+'('+chr(39)+'os'+chr(39)+')'), chr(95)*2+'doc'+chr(99-4)*2)"
>>> if is_it_safe(source):
... eval(source)
...
"OS routines for Mac, NT, or Posix depending ... "
Restricting Python is hard. No, not hard. It's *REALLY HARD*. Experts
have tried and failed. A good example is Tav's recent attempt to secure
Python code from *one* threat: writing a file on the local disk. Should
be simple, right?
If only.
http://tav.espians.com/a-challenge-to-break-python-security.html
The first exploit came an hour after Tav went public.
You can read the discussion on the Python-Dev list starting here:
http://mail.python.org/pipermail/python-dev/2009-February/086401.html
More here:
http://tav.espians.com/paving-the-way-to-securing-the-python-interpreter.html
http://tav.espians.com/update-on-securing-the-python-interpreter.html
My recommendation is that you do one of these:
(1) Give up on making your code "safe". Recognise that the threat is
relatively small, but real, and put a warning in your documentation about
the risk to user's own system if they evaluate arbitrary code, and then
just use eval and hope for the best.
(2) Decide that you don't want your calculate to be a full-fledged
programming language, and give up on making eval safe. Write your own
mini-parser to do arithmetic expressions. It's really not that difficult:
really easy with PyParsing, and not that hard without.
--
Steven
More information about the Python-list
mailing list