如何验证用户输入表达式,确保结果为布尔值,并限制python中使用的变量和方法?

如何验证用户输入表达式,确保结果为布尔值,并限制python中使用的变量和方法?,python,python-2.7,validation,abstract-syntax-tree,Python,Python 2.7,Validation,Abstract Syntax Tree,我的目的是验证用户输入表达式是否安全、合法和有效。例如,表达式可以是: exp = '''((value[0] == "failed" or value[0] == "blocked" or value[0] == "errored") and value[1] == "passed") ''' 正如评论中指出的,eval()不是验证的好方法。以下是我的限制: 表达式中仅使用变量“value” 字典中只允许有限数量的方法,例如: safe_methods = ['cos', 'sum', '

我的目的是验证用户输入表达式是否安全、合法和有效。例如,表达式可以是:

exp = '''((value[0] == "failed" or value[0] == "blocked" or value[0] == "errored") and value[1] == "passed") '''
正如评论中指出的,eval()不是验证的好方法。以下是我的限制:

  • 表达式中仅使用变量“value”
  • 字典中只允许有限数量的方法,例如:

    safe_methods = ['cos', 'sum', 'sin']
    
  • 表达式必须生成一个布尔结果,要么为True,要么为False

表达式的语法可以通过代码进行检查:

st = parser.expr(exp)
并检查是否引发了解析器异常。
我的问题是如何将所有这些约束应用于表达式?

我相信您试图做的是标记“value”数组中某些标记的任何出现。类似的东西

def doesContain (token, alist): return (token in alist) flagged=0 value=['failed','passed'] if (doesContain('failed',value)): print "contains failed\n" flagged+=1 if (doesContain('blocked',value)): print "contains blocked\n" flagged+=1 if (doesContain('errored',value)): print "contains errored\n" flagged+=1 if (flagged > 0): print ("%s items where flagged\n" % (flagged)) def doesContain(标记,列表): 返回(列表中的标记) 标记=0 值=['failed','passed'] 如果(doesContain('failed',value)): 打印“包含失败\n” 标记+=1 如果(doesContain('blocked',value)): 打印“包含被阻止的内容\n” 标记+=1 如果(doesContain('errored',value)): 打印“包含错误\n” 标记+=1 如果(标记为>0): 打印(“%s个已标记的项目\n”%(已标记))
我使用ast包解析用户输入,并重写visit函数以确保在用户输入表达式中只使用安全的方法和变量。 此外,不允许使用赋值运算符,以确保返回布尔变量。首先使用ast模块将字符串解析为抽象语法树。ast是一个树,其中每个节点表示一个类似于实体的操作符,python语法中的表达式。ast中的visit()方法使用访问者设计模式,从树上向下访问每个节点,并根据节点的类型调用相应的visit函数。这里的关键是覆盖visit_名称和visit_Assign函数,以便满足条件

import ast
SAFE_LIST = ['sum', 'len', 'max', 'min', 'abs', 'float', 'True', 'False', ' 
    value']
class allnames(ast.NodeVisitor):
    def visit_Module(self, node):
        self.names = set()
        self.assign = False
        self.generic_visit(node)
        for value in self.names:
            if value not in SAFE_LIST:
                return 'Variables other than value is used'
        if self.assign:
            return 'Assignment operator is used'
        return True

    def visit_Name(self, node):
        self.names.add(node.id)

    def visit_Assign(self, node):
        self.assign = True
        self.generic_visit(node)

rule = 'value = 1 or value(3) or ((sum(value) == 1 or value[0] == "failed" or value[0] ==  "blocked" or value[0] == "errored") and value[1] == "passed") or ((value[0] == "failed") and value[1] == "blocked") or ((value[0] == "blocked") and value[1] == "failed") or ((value[0] == "errored") and value[1] == "failed") or ((value[0] == "errored") and value[1] == "blocked")'
t = ast.parse(rule)
print(allnames().visit(t))

你为什么要这样做?那没有任何意义。无论是否短路,表达式的结果都是相同的。短路可能成为问题的唯一方式是,如果表达式的某些部分有副作用——如果是这种情况,代码会发出异味。“我的目的是使用eval函数验证[…]表达式是否有效[…]——不要这样做
eval
不应用于未知内容,尤其是在您以前没有验证过的情况下。调用
eval
不是验证任何内容的好方法如果要验证语法,请使用
ast
模块对其进行解析。这样,您甚至不需要对表达式求值,也不会出现短路之类的运行时行为。
eval
是一个支撑。如果您希望从表达式中获得的语义与Python的语义不匹配,则Python表达式计算器是错误的工作工具。如果您希望执行某种验证而不是任意代码执行,则尤其如此。Ast将是正确的方式。有人可以投票关闭这个帖子吗?