Verwenden Sie Ast- und Whitelists, um Pythons eval () sicher zu machen?

OK. ichkennt das Experten haben gesprochen und du solltest nichtje benutze Pythonseval() auf nicht vertrauenswürdigen Daten. Ich bin nicht schlauer als der Rest der Welt und sollte es nicht einmal versuchen. Aber! Ich werde sowieso.

Mein grundlegendes Problem ist, dass ich ein kleines Rechnerauswertungsprogramm schreiben möchte, das nicht vertrauenswürdige Eingaben unter Verwendung einer Teilmenge der Python-Syntax akzeptiert. Ich weiß: benutzeply oderPyparsing und schreibe einen Parser und los geht's. Herumspielen mit vorbeikommenden Globals und Einheimischen aneval() werde den Trick nicht tun.

Alle Ansätze, die ich gesehen habe (und bei denen ich misstrauisch war), versuchen, das Böse aufzuzählen. Hier versuche ich aufzuzählengut - Holen Sie sich einen AST, lassen Sie nur einige Knotentypen zu und überprüfen Sie, ob alle Aufrufe eine der Whitelist-Funktionen betreffen. Hier ist eine Mini-Implementierung (undein Kern):

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

So,my_safe_eval('2*(4+exp(1.3))') funktioniert, währendmy_safe_eval('[].__class__') Tricks undmy_safe_eval('open("/something/evil")') ist ebenfalls verboten - ohne zu verbieten__builtins__ oder__locals__ oder irgendwas.

Ich denke, das funktioniert. Bin ich verrückt?

Antworten auf die Frage(2)

Ihre Antwort auf die Frage