Используя ast и белые списки, чтобы сделать eval () python безопасным?

ХОРОШО. язнать  эксперты иметь разговорный и ты не долженКогда-либо использовать питонаeval() на ненадежных данных, когда-либо. Я'я не умнее остального мира и не должендаже не попробуй это. Но! Я'Я собираюсь, во всяком случае.

Моя основная проблема в том, что яя хочу написать небольшую программу-калькулятор, котораяприму ненадежный ввод, используя подмножество Python 'Синтаксис. Я знаю: использоватькурсировать или же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))

Так,my_safe_eval('2*(4+exp(1.3))') работает, покаmy_safe_eval('[].__class__') трюки иmy_safe_eval('open("/something/evil")') также запрещено - без запрета__builtins__ или же__locals__ или что-нибудь.

Я ... я думаю, что это работает. Я сумасшедший?

Ответы на вопрос(2)

Ваш ответ на вопрос