views:

327

answers:

4

I'm looking for a "safe" eval function, to implement spreadsheet-like calculations (using numpy/scipy).

The functionality to do this (the rexec module) has been removed from Python since 2.3 due to apparently unfixable security problems. There are several third-party hacks out there that purport to do this - the most thought-out solution that I have found is this Python Cookbok recipe, "safe_eval".

Am I reasonably safe if I use this (or something similar), to protect from malicious code, or am I stuck with writing my own parser? Does anyone know of any better alternatives?

EDIT: I just discovered RestrictedPython, which is part of Zope. Any opinions on this are welcome.

+2  A: 

Writing your own parser could be fun! It might be a better option because people are expecting to use the familiar spreadsheet syntax (Excel, etc) and not Python when they're entering formulas. I'm not familiar with safe_eval but I would imagine that anything like this certainly has the potential for exploitation.

pix0r
+1  A: 

Although that code looks quite secure, I've always held the opinion that any sufficiently motivated person could break it given adequate time. I do think it will take quite a bit of determination to get through that, but I'm relatively sure it could be done.

dwestbrook
A: 

Daniel, Jinja implements a sandboxe environment that may or may not be useful to you. From what I remember, it doesn't yet "comprehend" list comprehensions.

Sanbox info

John Douthat
+1  A: 

Depends on your definition of safe I suppose. A lot of the security depends on what you pass in and what you are allowed to pass in the context. For instance, if a file is passed in, I can open arbitrary files:

>>> names['f'] = open('foo', 'w+')
>>> safeeval.safeeval("baz = type(f)('baz', 'w+')", names)
>>> names['baz']
<open file 'baz', mode 'w+' at 0x413da0>

(above safeeval = safe_eval, the code block seems to break on underscores)

Furthermore, the environment is very restricted (you cannot pass in modules), thus, you can't simply pass in a module of utility functions like re or random.

On the other hand, you don't need to write your own parser, you could just write your own evaluator for the python ast:

>>> import compiler
>>> ast = compiler.parse("print 'Hello world!'")

That way, hopefully, you could implement safe imports. The other idea is to use Jython or IronPython and take advantage of Java/.Net sandboxing capabilities.

Aaron Maenpaa