6

好的。我知道 专家们已经说过,你永远不应该 不受信任的数据上使用 python 。我并不比世界其他人聪明,甚至不应该尝试这个。但!不管怎样,我要去。 eval()

我的基本问题是,我正在寻找使用 python 语法的子集编写一个小型计算器评估程序,该程序将接受不受信任的输入。我知道:使用plypyparsing并编写一个解析器,然后就可以了。与传递的全局变量和本地变量一起乱搞是eval()行不通的。

我见过的所有方法(并且一直持怀疑态度)都试图列举邪恶。在这里,我试图列举好的——获取一个 AST,只允许少数节点类型,然后验证任何调用都是针对一组白名单函数中的一个。这是一个小型实现(和要点):

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))

所以,my_safe_eval('2*(4+exp(1.3))')工作,而my_safe_eval('[].__class__')欺骗,my_safe_eval('open("/something/evil")')同样被禁止——没有禁止__builtins____locals__任何东西。

我...我认为这行得通。我疯了吗?

4

2 回答 2

3

Zope 有一个叫做RestrictedPython的东西,你可能想检查一下,至少是为了验证你的方法或者可能重用他们的代码。它是可配置和可重复使用的。

这是对类似问题的另一个回答。

于 2012-09-21T02:55:07.160 回答
2

试试asteval,似乎是你需要的东西。否则有这个安全的评估

于 2013-01-25T10:04:19.363 回答