Question about ast.literal_eval

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon May 20 12:12:27 EDT 2013


On Mon, 20 May 2013 15:26:02 +0200, Frank Millman wrote:

> Can anyone see anything wrong with the following approach. I have not
> definitely decided to do it this way, but I have been experimenting and
> it seems to work.
> 
> I store the boolean test as a json'd list of 6-part tuples. Each element
> of the tuple is a string, defined as follows -
> 
> 0 - for the first entry in the list, the word 'check' (a placeholder -
> it is discarded at evaluation time), for any subsequent entries the word
> 'and' or 'or'.
> 
> 1 - left bracket - either '(' or ''.
> 
> 2 - column name to check - it will be validated on entry.
> 
> 3 - operator - must be one of '=', '!=', '<', '>', '<=', '>=', 'in',
> 'is', 'is not'. At evaluation time, '=' is changed to '=='.
> 
> 4 - value to compare - at evaluation time I call
> str(literal_eval(value)) to ensure that it is safe.
> 
> 5 - right bracket - either ')' or ''.
> 
> At evaluation time I loop through the list, construct the boolean test
> as a string, and call eval() on it.
[...]
> It seems safe to me. Can anyone see a problem with it?


It seems safe to me too, but then any fool can come up with a system 
which they themselves cannot break :-)

I think the real worry is validating the column name. That will be 
critical. Personally, I would strongly suggest writing your own mini-
evaluator that walks the list and evaluates it by hand. It isn't as 
convenient as just calling eval, but *definitely* safer.

If you do call eval, make sure you supply the globals and locals 
arguments. The usual way is:

eval(expression, {'__builtins__': None}, {})

which gives you an empty locals() and a minimal, (mostly) safe globals.

Finally, as a "belt-and-braces" approach, I wouldn't even call eval 
directly, but call a thin wrapper that raises an exception if the 
expression contains an underscore. Underscores are usually the key to 
breaking eval, so refusing to evaluate anything with an underscore raises 
the barrier very high.

And even with all those defences, I wouldn't allow untrusted data from 
the Internet anywhere near this. Just because I can't break it, doesn't 
mean it's safe.


-- 
Steven



More information about the Python-list mailing list