Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing ast and whitelists to make python's eval() safe?
    primarykey
    data
    text
    <p>OK. I <a href="https://stackoverflow.com/questions/3513292/python-make-eval-safe">know</a> <a href="https://stackoverflow.com/questions/1994071/how-safe-is-expression-evaluation-using-eval">the</a> <a href="https://stackoverflow.com/questions/28369/is-safe-eval-really-safe">experts</a> <a href="https://stackoverflow.com/questions/5351059/is-this-a-safe-use-of-python-eval">have</a> <a href="http://me.veekun.com/blog/2012/03/24/on-principle/" rel="nofollow noreferrer">spoken</a> and you should not <em>ever</em> use python's <code>eval()</code> on untrusted data, ever. I'm not smarter than the rest of the world, and shouldn't even try this. But! I'm going to, anyhow.</p> <p>My basic problem is that I'm looking to write a little calculator evaluator program that'll take untrusted input, using a subset of python's syntax. I know: use <a href="http://www.dabeaz.com/ply/" rel="nofollow noreferrer">ply</a> or <a href="http://pyparsing.wikispaces.com/" rel="nofollow noreferrer">pyparsing</a> and write a parser and there we go. Screwing around with passing globals and locals to <code>eval()</code> will not do the trick.</p> <p>All the approaches I've seen (and been leery about) try to enumerate evil. Here, I'm trying to enumerate <em>good</em> -- get an AST, allow only a few node types, and then verify that any calls are to one of a set of whitelisted functions. Here's a mini-implementation (and <a href="https://gist.github.com/3759435" rel="nofollow noreferrer">a gist</a>):</p> <pre class="lang-py prettyprint-override"><code>import ast import math SAFE_FX = { 'exp': math.exp, } SAFE_NODES = set( (ast.Expression, ast.Num, ast.Call, ast.Name, ast.Load, ast.BinOp, ast.Add, ast.Sub, ast.Mult, ast.Div,) ) class CleansingNodeVisitor(ast.NodeVisitor): def generic_visit(self, node): if type(node) not in SAFE_NODES: raise Exception("%s not in SAFE_NODES" % type(node)) super(CleansingNodeVisitor, self).generic_visit(node) def visit_Call(self, call): if call.func.id not in SAFE_FX: raise Exception("Unknown function: %s" % call.func.id) def my_safe_eval(s): tree = ast.parse(s, mode='eval') cnv = CleansingNodeVisitor() cnv.visit(tree) compiled = compile(tree, s, "eval") return(eval(compiled, SAFE_FX)) </code></pre> <p>So, <code>my_safe_eval('2*(4+exp(1.3))')</code> works, while <code>my_safe_eval('[].__class__')</code> tricks and <code>my_safe_eval('open("/something/evil")')</code> is likewise forbidden -- without forbidding <code>__builtins__</code> or <code>__locals__</code> or anything.</p> <p>I... I think this works. Am I mad?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload