safe eval of moderately simple math expressions

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Apr 11 12:46:45 CEST 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