Nat*_*ate 5 python security parsing eval
好.我知道 的 专家 都 讲,你不应该永远使用Python的eval()不受信任的数据,直到永远.我并不比世界其他地方更聪明,甚至不应该尝试这个.但!无论如何,我要去.
我的基本问题是我正在编写一个小计算器评估程序,它将使用python语法的一个子集进行不可信的输入.我知道:使用ply或pyparsing并编写解析器然后我们去.通过传递全局和本地人来解决这个问题是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))
Run Code Online (Sandbox Code Playgroud)
所以,my_safe_eval('2*(4+exp(1.3))')作品,而my_safe_eval('[].__class__')技巧和my_safe_eval('open("/something/evil")')同样是禁止的-没有禁止__builtins__或__locals__什么的.
我......我觉得这很有效.我疯了吗?
| 归档时间: |
|
| 查看次数: |
2298 次 |
| 最近记录: |