Python中如何安全验证用户输入表达式?限制变量方法且确保结果为布尔值
Validate Safe, Legal Boolean Expressions (Without
eval()) Great question—using eval() directly is a huge security risk here, since it can execute arbitrary code. Instead, we can use Python's built-in ast module to parse the expression into an abstract syntax tree (AST), then validate every node against your constraints. This way, we never execute the untrusted expression, just analyze its structure.
Key Constraints to Enforce
We need to lock down three critical rules:
- Only the variable
valueis allowed (no other variables permitted) - Any method calls must be from your
safe_methodslist (e.g.,cos,sum,sin) - The expression must evaluate to a boolean result
Step-by-Step Implementation
Here's a complete, reusable solution that checks all your requirements:
import ast from typing import List class ExpressionValidator(ast.NodeVisitor): def __init__(self, safe_methods: List[str]): self.safe_methods = set(safe_methods) self.invalid_variable_found = False self.invalid_method_found = False self.returns_boolean = False def visit_Name(self, node: ast.Name) -> None: # Ensure all variables are exactly 'value' if node.id != 'value': self.invalid_variable_found = True self.generic_visit(node) def visit_Call(self, node: ast.Call) -> None: # Check that any method called is in our safe list if isinstance(node.func, ast.Attribute): method_name = node.func.attr if method_name not in self.safe_methods: self.invalid_method_found = True self.generic_visit(node) def visit_Module(self, node: ast.Module) -> None: # Verify the top-level expression produces a boolean if isinstance(node.body[0], ast.Expr): expr = node.body[0].value # Boolean expressions are typically comparisons, boolean ops, or boolean constants valid_bool_node_types = (ast.Compare, ast.BoolOp, ast.Constant) if isinstance(expr, valid_bool_node_types): # For constants, make sure it's actually a boolean (not a number/string) if isinstance(expr, ast.Constant) and not isinstance(expr.value, bool): self.returns_boolean = False else: self.returns_boolean = True else: self.returns_boolean = False self.generic_visit(node) def validate_expression(expr_str: str, safe_methods: List[str]) -> bool: try: # Parse the expression into an AST tree = ast.parse(expr_str, mode='eval') except SyntaxError: # Invalid Python syntax means the expression is automatically invalid return False validator = ExpressionValidator(safe_methods) validator.visit(tree) # All checks must pass to return True return (not validator.invalid_variable_found and not validator.invalid_method_found and validator.returns_boolean)
How to Use It
Test it against your sample expression and edge cases to see it in action:
# Your sample valid expression exp = '''((value[0] == "failed" or value[0] == "blocked" or value[0] == "errored") and value[1] == "passed") ''' safe_methods = ['cos', 'sum', 'sin'] print(validate_expression(exp, safe_methods)) # Output: True # Test invalid scenarios invalid_var_expr = 'other_var == 5' print(validate_expression(invalid_var_expr, safe_methods)) # Output: False (uses forbidden variable) invalid_method_expr = 'value.sum() == 10' print(validate_expression(invalid_method_expr, ['cos'])) # Output: False (sum not in safe methods) non_bool_expr = 'value[0] + value[1]' print(validate_expression(non_bool_expr, safe_methods)) # Output: False (result isn't a boolean)
Why This Works
- AST Parsing: We analyze the expression's structure without executing it, eliminating the risk of arbitrary code execution that comes with
eval(). - Granular Checks: The
ExpressionValidatorwalks every node in the tree to enforce your variable and method restrictions. - Type Validation: We ensure the top-level expression produces a boolean by checking the AST node types (comparisons, boolean operators, or boolean constants).
内容的提问来源于stack exchange,提问作者Xiaojun Yu
相关产品推荐
相关产品推荐

