在Python中更安全的' eval ' ?



我如何使这段代码更安全?这是一个更复杂代码的最小可复制示例,其中允许内部用户对代码中的几个字典进行读访问,这些字典的名称是预先知道的。该示例在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是危险的,没有必要重复警告。

相关:
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这样的库用于此目的。

要访问变量(#安全),您可以使用vars()函数
和regex来添加更多的功能:

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()返回一个字典,其中包含该范围内的所有变量名及其值。在这种情况下,因为我使用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

最新更新