python安全eval执行一般计算

import ast
import re
from _ast import *
_NUM_TYPES = (int, float, complex)

def literal_eval(node_or_string):
    """
    Safely evaluate an expression node or a string containing a Python
    expression.  The string or node provided may only consist of the following
    Python literal structures: strings, bytes, numbers, tuples, lists, dicts,
    sets, booleans, and None.
    """
    if isinstance(node_or_string, str):
        node_or_string = ast.parse(node_or_string, mode='eval')
    if isinstance(node_or_string, Expression):
        node_or_string = node_or_string.body
    def _convert(node):
        if isinstance(node, Constant):
            return node.value
        elif isinstance(node, (Str, Bytes)):
            return node.s
        elif isinstance(node, Num):
            return node.n
        elif isinstance(node, Tuple):
            return tuple(map(_convert, node.elts))
        elif isinstance(node, List):
            return list(map(_convert, node.elts))
        elif isinstance(node, Set):
            return set(map(_convert, node.elts))
        elif isinstance(node, Dict):
            return dict((_convert(k), _convert(v)) for k, v
                        in zip(node.keys, node.values))
        elif isinstance(node, NameConstant):
            return node.value
        elif isinstance(node, UnaryOp) and isinstance(node.op, (UAdd, USub)):
            operand = _convert(node.operand)
            if isinstance(operand, _NUM_TYPES):
                if isinstance(node.op, UAdd):
                    return + operand
                else:
                    return - operand
        elif isinstance(node, BinOp) and isinstance(node.op, (Add, Sub)):
            left = _convert(node.left)
            right = _convert(node.right)
            if isinstance(left, _NUM_TYPES) and isinstance(right, _NUM_TYPES):
                if isinstance(node.op, Add):
                    return left + right
                else:
                    return left - right
        elif isinstance(node, BinOp) and isinstance(node.op, (Mult, Div)):
            left = _convert(node.left)
            right = _convert(node.right)
            if isinstance(left, _NUM_TYPES) and isinstance(right, _NUM_TYPES):
                if isinstance(node.op, Mult):
                    return left * right
                else:
                    return left / right
        elif isinstance(node, Compare) and all([isinstance(x, (Lt, LtE, Gt, GtE, Eq, NotEq)) for x in node.ops]):
            left = _convert(node.left)
            comparators = [_convert(comparator) for comparator in node.comparators]
            if len(comparators) == len(node.ops):
                for i in range(len(node.ops)):
                    op = node.ops[i]
                    comparator = comparators[i]
                    if isinstance(left, _NUM_TYPES) and isinstance(comparator, _NUM_TYPES):
                        if isinstance(op, Lt):
                            result = (left < comparator)
                        elif isinstance(op, LtE):
                            result = (left <= comparator)
                        elif isinstance(op, Gt):
                            result = (left > comparator)
                        elif isinstance(op, GtE):
                            result = (left >= comparator)
                        elif isinstance(op, Eq):
                            result = (left == comparator)
                        elif isinstance(op, NotEq):
                            result = (left != comparator)
                        else:
                            break
                        left = comparator
                        if not result:
                            return False
                else:
                    return True
        elif isinstance(node, BoolOp) and isinstance(node.op, (And, Or)):
            values = node.values
            if len(values) == 2:
                left = _convert(values[0])
                right = _convert(values[1])
                if (isinstance(left, _NUM_TYPES) or isinstance(left, (NameConstant, Constant))) and (isinstance(right, _NUM_TYPES) or isinstance(right, (NameConstant, Constant))):
                    if isinstance(node.op, And):
                        return left and right
                    elif isinstance(node.op, Or):
                        return left or right
        elif isinstance(node, UnaryOp) and isinstance(node.op, (Not, )):
            value = _convert(node.operand)
            if isinstance(value, _NUM_TYPES) or isinstance(value, (NameConstant, Constant)):
                return not value
        raise ValueError('malformed node or string: ' + repr(node))
    return _convert(node_or_string)

python中eval功能十分强大, 但是同时安全漏洞也很明显, 通过__import__('os').system方法, 可以通过字符串eval方式执行任意cmd, 所以通常不采用eval去做功能, 但有些时候, 一些需求需要用到动态计算, 如果单纯通过模型间关系去做几乎不可能, 如果通过解析引擎去动态计算, 构建引擎的复杂度本身就超过了计算的复杂度, 通过资料的查找, 可以通过ast的literal_eval的方式去执行计算, 但是改方法本身只支持加减运算, 通过对源码copy修改后, 即可放开对乘除的计算, 代码如上

2023/1/3更新

增加了对小于、大于、等于、不等于、且、或、非等判断的支持

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值