¿Usar ast y las listas blancas para hacer que eval () de python sea seguro?

DE ACUERDO. yosaber la expertos tener hablado y no deberíassiempre usar pythoneval() en datos no fiables, nunca. No soy más inteligente que el resto del mundo, y ni siquiera debería intentar esto. ¡Pero! Voy a, de todos modos

Mi problema básico es que estoy buscando escribir un pequeño programa de evaluación de calculadoras que tomará información no confiable, usando un subconjunto de la sintaxis de python. Lo se: usarcapa opyparsing Y escribo un parser y ahí vamos. Atornillando alrededor con globales y locales paraeval() no va a hacer el truco

Todos los enfoques que he visto (y he estado preocupado por) tratan de enumerar el mal. Aquí, estoy tratando de enumerarbueno - obtenga un AST, permita solo algunos tipos de nodos, y luego verifique que todas las llamadas sean a una de un conjunto de funciones incluidas en la lista blanca. Aquí hay una mini-implementación (yuna esencia):

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

Asi que,my_safe_eval('2*(4+exp(1.3))') trabaja, mientrasmy_safe_eval('[].__class__') trucos ymy_safe_eval('open("/something/evil")') Está igualmente prohibido, sin prohibiciones.__builtins__ o__locals__ o algo.

Yo ... creo que esto funciona. ¿Estoy loco?

Respuestas a la pregunta(2)

Su respuesta a la pregunta