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

如何让eval()仅支持算术表达式与指定函数?求替代方案

解决eval()安全风险的计算器优化方案

一、限制eval()的执行范围(最小权限原则)

直接使用eval()会继承当前全局命名空间,恶意用户可输入__import__('os').system('rm -rf /')这类代码执行危险操作。通过指定globals和locals参数,能严格限制eval可访问的内容:

  1. 明确导入允许的函数
    替换from mymathmodule import *为精准导入,避免引入不必要的对象:
from mymathmodule import percentagecalc, factorialcalc, factorial, sqrt  # 仅导入需要开放的函数
import time
  1. 构建安全命名空间
    创建仅包含允许的内置算术函数和自定义函数的命名空间,彻底隔离危险内置对象:
# 允许使用的内置算术函数
safe_builtins = {
    'abs': abs,
    'pow': pow,
    'round': round,
    'sum': sum,
}

# 组合自定义安全函数到全局命名空间
safe_globals = {
    '__builtins__': safe_builtins,
    'factorial': factorial,
    'sqrt': sqrt
}
  1. 修改eval调用
    在基础算术模块中,使用安全命名空间调用eval:
elif a == 3:
    calc = input("Enter Expression:")
    try:
        result = eval(calc, safe_globals, {})
        print("Expression equals:", result)
    except Exception as e:
        print(f"\nInvalid expression: {str(e)}")
        time.sleep(0.6)

这样用户只能使用你指定的函数和基础算术运算,无法执行任何超出范围的代码。

二、eval()的安全替代方案

如果想彻底规避eval()的风险,推荐使用ast模块解析表达式语法树,手动控制允许的操作,安全性更高:

方案1:基于ast模块的安全求值

import ast
from mymathmodule import percentagecalc, factorialcalc, factorial, sqrt
import time

# 允许的算术操作符
ALLOWED_OPS = {
    ast.Add, ast.Sub, ast.Mult, ast.Div, ast.Pow, ast.Mod,
    ast.UAdd, ast.USub
}

# 允许调用的函数
ALLOWED_FUNCTIONS = {
    'factorial': factorial,
    'sqrt': sqrt,
    'abs': abs,
    'pow': pow,
    'round': round
}

def safe_eval(expr):
    # 解析表达式为语法树
    try:
        tree = ast.parse(expr, mode='eval')
    except SyntaxError:
        raise ValueError("Invalid expression syntax")
    
    # 遍历语法树,检查所有节点合法性
    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            # 禁止调用未授权函数
            if not isinstance(node.func, ast.Name) or node.func.id not in ALLOWED_FUNCTIONS:
                raise ValueError(f"Function '{node.func.id}' is not allowed")
        elif isinstance(node, ast.Constant):
            # 允许常量(数字、布尔值等)
            continue
        elif type(node) not in ALLOWED_OPS:
            # 禁止未授权操作
            raise ValueError(f"Operation '{type(node).__name__}' is not allowed")
    
    # 在安全命名空间中执行表达式
    return eval(compile(tree, filename='', mode='eval'), {'__builtins__': None}, ALLOWED_FUNCTIONS)

# 修改主循环中的基础算术部分
while True:
    try:   
        Choose = '''Choose your function:
        1: Percentage calculator
        2: Factorial calculator
        3: Basic arithmetics (+-*/)
        '''
        for character in Choose:
            print(character, end="", flush=True)
            time.sleep(0.006)
        a = int(input(':'))
        if a == 1:
            percentagecalc()
        elif a == 2:
            factorialcalc()
        elif a == 3:
            calc = input("Enter Expression:")
            try:
                result = safe_eval(calc)
                print("Expression equals:", result)
            except ValueError as e:
                print(f"\nError: {e}")
                time.sleep(0.6)
        else:
            print("\nOops! Error.  Try again...") 
        time.sleep(0.6)
    except Exception as e:
        print(f"\nOops! Error: {str(e)}.  Try again...")    
        time.sleep(0.6)

该方法通过语法树检查,完全禁止任何未授权的操作和函数调用,安全性远高于直接使用eval()。

方案2:使用第三方库(可选)

如果不想手动实现语法树检查,可使用simpleeval库,它支持配置允许的函数和操作符,使用更简洁:

from simpleeval import SimpleEval

# 初始化求值器并添加允许的函数
se = SimpleEval()
se.functions['factorial'] = factorial
se.functions['sqrt'] = sqrt

# 使用时直接调用
result = se.eval(calc)

需先通过pip install simpleeval安装该库。

内容的提问来源于stack exchange,提问作者SK-the-Learner

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 23:57:22