Python 中的“eval”更安全?

Safer `eval` in Python?

我怎样才能使这段代码更安全?这是一个更复杂代码的最小可重现示例,其中允许内部用户读取代码中的一些字典,他们的名字是事先知道的。该示例与 eval 一起正常工作,并防止 某些 恶意用户输入,例如对 rm -rf / 的系统调用。但我一直在寻找比 eval.

更安全的方法
import re

# In the minimal example, I have 2 dicts that the users need 
# read access to, and keys match this regex: ^\w+$
dct_a = {'foo': 1, 'bar': 2}
dct_b = {'baz': 3, 'bletch': 4}

# User input, e.g.:
lst = ["dct_a['foo']", "dct_b['baz']"]

for item in lst:
    # Make safer, prevent a few obvious hacks:
    if not re.findall(r"^[\w\]\[']+$", item):
        raise Exception(f'Unsafe item: {item}')
    # do something with item, e.g.:
    print(eval(item))

# Prints:
# 1
# 3

我知道 eval is dangerous,无需重复警告。

相关:
Python: make eval safe

与其从 Python 的全部功能开始并试图控制它(这是愚蠢的差事),不如从你需要的开始,这不允许用户做任何其他事情因为它不能做任何其他事情。您不希望您的用户能够 运行 Python 代码,您希望您的用户能够以某种非常有限的方式指定“变量值”。所以,例如:

vals = {
    'a': {'foo': 1, 'bar': 2},
    'b': {'baz': 3, 'bletch': 4}
}

# User input, e.g.:
lst = ["a.foo", "b.baz"]

for item in lst:
    dct, k = item.split('.')
    print(vals[dct][k])

如果这就是您的用户需要做的所有事情,那么这就是您所需要的。从这里开始,您当然可以开始编写自己的迷你语言,以获得越来越强大但仍然非常有限和受限的表达方式。为此目的,有像 pyparsing 这样的库。

要访问变量(#safely)你可以使用vars()函数
并使用正则表达式为其添加更多功能:

import re

dct_a = {'foo': 1, 'bar': 2}
dct_b = {'baz': 3, 'bletch': 4}

for _ in range(5):
    try:
        cmd = input(">>> ")
        cmds = re.findall(r'(\w+)\[\'?\"?(\w+)\'?\"?\]',cmd)
        if cmds:
            print(vars()[cmds[0][0]][cmds[0][1]])
        else:
            print(vars()[cmd])
    except Exception as e:
        print(cmd,'Not in Scope')

vars() returns 一个字典,所有变量名作为 keys 和它们的值作为 values,在那个范围内。在这种情况下,因为我使用了没有任何参数的 vars,所以它等同于 locals(),并且也可以用来代替 vars

globals()是一个类似的方法,但是顾名思义,它只访问全局变量。

输出:

>>> dct_a
{'foo': 1, 'bar': 2}

>>> dct_a['bar']
2

>>> dct_b
{'baz': 3, 'bletch': 4}

>>> dct_b["baz"]
3

>>> dct_c
dct_c Not in Scope