
本文介绍如何安全、灵活地解析并执行用户通过 JSON 等外部配置提供的动态条件表达式(如 (Bob.age == Jane.age) || (Bob.age本文介绍如何安全、灵活地解析并执行用户通过 json 等外部配置提供的动态条件表达式(如 `(bob.age == jane.age) || (bob.age
在构建报表系统、规则引擎或低代码平台时,常需支持用户以声明式方式编写逻辑条件(例如
"Bob.age > 30 and Jane.age ),再由后端动态求值。虽然 Python 的 <code>eval()函数看似便捷,但它会执行任意代码,存在严重安全隐患——一旦用户输入恶意语句(如__import__('os').system('rm -rf /')),将导致服务被入侵。✅ 推荐方案:使用
pyparsing构建安全表达式解析器pyparsing是成熟、轻量、可定制的语法解析库,适合构建受限但语义清晰的条件语言。以下是一个最小可行示例:from pyparsing import infixNotation, opAssoc, Word, alphas, nums, Suppress, oneOf, Group # 定义变量名(如 Bob.age、Jane.age) identifier = Word(alphas, alphas + nums + "._") # 定义数字字面量(支持整数) number = Word(nums).setParseAction(lambda t: int(t[0])) # 定义原子表达式:变量或数字 atom = identifier | number # 支持的比较运算符 comparison_op = oneOf("== != < <= > >=") boolean_op = oneOf("and or") # 构建条件表达式语法(支持括号、优先级) expr = infixNotation( atom, [ (comparison_op, 2, opAssoc.LEFT), (boolean_op, 2, opAssoc.LEFT), ] ) # 数据上下文(模拟你的固定表) context = { "Bob.age": 47, "Bill.age": 44, "Jane.age": 36, "Steve.age": 22, } def safe_eval(token): if isinstance(token, str): return context.get(token, 0) # 未定义变量返回默认值(或抛异常) return token def evaluate(parsed): if isinstance(parsed, list): if len(parsed) == 3 and parsed[1] in ("==", "!=", "<", "<=", ">", ">="): left, op, right = parsed lval = safe_eval(evaluate(left)) rval = safe_eval(evaluate(right)) return { "==": lambda a, b: a == b, "!=": lambda a, b: a != b, "<": lambda a, b: a < b, "<=": lambda a, b: a <= b, ">": lambda a, b: a > b, ">=": lambda a, b: a >= b, }[op](lval, rval) elif parsed[1] == "and": return evaluate(parsed[0]) and evaluate(parsed[2]) elif parsed[1] == "or": return evaluate(parsed[0]) or evaluate(parsed[2]) return safe_eval(parsed) # 使用示例 user_condition = "(Bob.age == Jane.age) or (Bob.age < Bill.age)" parsed = expr.parseString(user_condition, parseAll=True)[0] result = evaluate(parsed) print(result) # 输出: True⚠️ 注意事项:
- 永远避免
eval()/exec()处理不可信输入;即使加了__builtins__={}仍可能被绕过;- 若需更强大语法(如函数调用
max(Bob.age, Jane.age)),可结合simpleeval库(专为安全数学/逻辑表达式设计);- JSON 配置中建议统一使用小写布尔运算符(
and/or),而非||/&&,以降低解析复杂度;- 实际部署时应增加超时控制与深度限制,防止正则回溯或无限递归攻击。
? 总结:动态条件求值不是“能否实现”,而是“如何安全实现”。选择
pyparsing或simpleeval可在可控语法范围内达成高灵活性与强安全性平衡,是工业级规则系统的主流实践。立即学习“Python免费学习笔记(深入)”;


















