You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django后端处理用户输入公式:替代eval的安全方案

安全处理Django中用户自定义计算公式的方案

针对你在Django应用中存储并计算用户自定义公式的需求,以下是几个避免eval/f-string安全风险的可靠方案:

1. 利用Python AST模块做安全解析

Python的ast模块可以将表达式解析为抽象语法树,你可以遍历树结构,只允许指定类型的节点(比如变量、算术操作、数字),过滤掉函数调用、属性访问等危险操作,确保执行的代码完全可控。

示例代码:

import ast

def safe_eval(formula, variables):
    # 将用户公式中的{var}格式替换为变量名
    cleaned_formula = formula.replace("{", "").replace("}", "")
    # 解析表达式为AST
    tree = ast.parse(cleaned_formula, mode='eval')
    
    # 定义允许的节点类型
    allowed_nodes = (ast.Expression, ast.BinOp, ast.Name, ast.Num,
                     ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Pow)
    
    # 遍历AST节点,检查是否有非法内容
    for node in ast.walk(tree):
        if not isinstance(node, allowed_nodes):
            raise ValueError(f"非法表达式内容: {type(node).__name__}")
    
    # 编译并执行安全的AST
    compiled = compile(tree, filename='', mode='eval')
    return eval(compiled, {}, variables)

# 使用示例
formula = "{rower_weight}/({rower_time})^3"
variables = {"rower_weight": 75, "rower_time": 12}
result = safe_eval(formula, variables)
print(result)

2. 使用第三方安全表达式库

比如simpleeval,它专门为安全计算表达式设计,支持自定义允许的变量、操作符和函数,默认会阻止所有危险操作。

步骤:

  1. 安装库:pip install simpleeval
  2. 编写计算逻辑:
from simpleeval import SimpleEval

def calculate_formula(formula, variables):
    cleaned_formula = formula.replace("{", "").replace("}", "")
    # 初始化计算器,只允许指定变量和算术操作
    evaluator = SimpleEval(names=variables)
    # 可以额外限制允许的操作符,比如只保留加减乘除幂
    evaluator.operators = {
        '+': evaluator.operators['+'],
        '-': evaluator.operators['-'],
        '*': evaluator.operators['*'],
        '/': evaluator.operators['/'],
        '**': evaluator.operators['**'],
    }
    return evaluator.eval(cleaned_formula)

# 使用示例
formula = "{rower_weight}/({rower_time})^3"
variables = {"rower_weight": 80, "rower_time": 10}
result = calculate_formula(formula, variables)
print(result)

3. 自定义简单表达式解析器(适合需求单一场景)

如果你的公式逻辑很简单(仅基础算术+变量),可以自己用正则或语法分析库(比如pyparsing)实现解析,完全掌控计算逻辑。

示例(用pyparsing):

  1. 安装库:pip install pyparsing
  2. 实现解析:
from pyparsing import Word, nums, alphas, Combine, oneOf, infixNotation, opAssoc

def build_parser():
    # 定义数字和变量
    number = Combine(Word(nums) + "." + Word(nums) | Word(nums))
    variable = Word(alphas + "_")
    # 定义操作符
    operators = oneOf("+ - * / **")
    # 构建表达式语法
    expr = infixNotation(number | variable,
        [
            ("**", 2, opAssoc.RIGHT),
            ("*", 2, opAssoc.LEFT),
            ("/", 2, opAssoc.LEFT),
            ("+", 2, opAssoc.LEFT),
            ("-", 2, opAssoc.LEFT),
        ])
    return expr

def evaluate_parsed_expr(parsed, variables):
    # 递归计算解析后的表达式
    if isinstance(parsed, str):
        if parsed in variables:
            return variables[parsed]
        return float(parsed)
    op = parsed[0]
    left = evaluate_parsed_expr(parsed[1], variables)
    right = evaluate_parsed_expr(parsed[2], variables)
    if op == '+':
        return left + right
    elif op == '-':
        return left - right
    elif op == '*':
        return left * right
    elif op == '/':
        return left / right if right != 0 else 0
    elif op == '**':
        return left ** right

def custom_calculate(formula, variables):
    cleaned_formula = formula.replace("{", "").replace("}", "")
    parser = build_parser()
    parsed = parser.parseString(cleaned_formula, parseAll=True)[0]
    return evaluate_parsed_expr(parsed, variables)

# 使用示例
formula = "{rower_weight}/({rower_time})^3"
variables = {"rower_weight": 70, "rower_time": 15}
result = custom_calculate(formula, variables)
print(result)

额外注意事项

  • 验证用户输入的变量名是否为系统允许的字段,避免非法变量导致的错误。
  • 添加异常处理,比如除法除以零、幂运算的非法输入等情况。
  • 存储公式时可以统一格式(比如去掉多余空格、统一变量占位符),减少解析时的问题。

内容的提问来源于stack exchange,提问作者Jack Miller

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 11:45:34