Question about ast.literal_eval

I am trying to emulate a SQL check constraint in Python. Quoting from
the PostgreSQL docs, "A check constraint is the most generic constraint
type. It allows you to specify that the value in a certain column must
satisfy a Boolean (truth-value) expression."

The problem is that I want to store the constraint as a string, and I
was hoping to use ast.literal_eval to evaluate it, but it does not work.
>>> x = 'abc'
>>> x in ('abc', xyz')
True
>>> b = "x in ('abc', 'xyz')"
>>> eval(b)
True
>>> from ast import literal_eval
>>> literal_eval(b)
ValueError: malformed node or string: <_ast.Compare object at ...>

This works by maintaining an internal namespace (a flat dictionary), and walking the AST generated for the expression. It supports most Python syntax,
including if, for, while, and try/except blocks, and function definitions, and with the notable exceptions of eval, exec, class, lambda, yield, and import. This requires Python2.6 and higher, and does work with Python3.3.

Of course, it is not guaranteed to be completely safe, but it does disallowimports, which seems like the biggest vulnerability concern listed here. Currently, there is no explicit protection against long-running calculations for denial of service attacks. If you're exposing an SQL database to user-generated code, that may be worth considering.

Advertisements

On 21/05/2013 04:39, wrote:
>
> You might find the asteval module (https://pypi.python.org/pypi/asteval) useful. It provides a relatively safe "eval", for example:
>
> >>> import asteval
> >>> a = asteval.Interpreter()
> >>> a.eval('x = "abc"')
> >>> a.eval('x in ("abc", "xyz")')
> True
> >>> a.eval('import os')
> NotImplementedError
> import os
> 'Import' not supported
> >>> a.eval('__import__("os")')
> NameError
> __import__("os")
> name '__import__' is not defined
>
> This works by maintaining an internal namespace (a flat dictionary), and walking the AST generated for the expression. It supports most Python syntax,
> including if, for, while, and try/except blocks, and function definitions, and with the notable exceptions of eval, exec, class, lambda, yield, and import. This requires Python2.6 and higher, and does work with Python3.3.
>
> Of course, it is not guaranteed to be completely safe, but it does disallow imports, which seems like the biggest vulnerability concern listed here. Currently, there is no explicit protection against long-running calculations for denial of service attacks. If you're exposing an SQL database to user-generated code, that may be worth considering.

Share This Page

Welcome to The Coding Forums!

Welcome to the Coding Forums, the place to chat about anything related to programming and coding languages.

Please join our friendly community by clicking the button below - it only takes a few seconds and is totally free. You'll be able to ask questions about coding or chat with the community and help others.
Sign up now!