我有一些代码的情况,其中eval()作为一个可能的解决方案。现在,我以前从未使用过eval(),但是,我遇到了大量关于它可能导致的潜在危险的信息。也就是说,我对使用它非常谨慎。

我的情况是,我有输入是由一个用户:

datamap = input('Provide some data here: ')

其中数据地图需要是一个字典。我搜索了一下,发现eval()可以解决这个问题。我认为我可以在尝试使用数据之前检查输入的类型,这将是一个可行的安全预防措施。

datamap = eval(input('Provide some data here: ')
if not isinstance(datamap, dict):
    return

我通读了所有的文件,但我仍然不清楚这样做是否安全。eval是否在数据输入或调用数据映射变量后立即计算数据?

ast模块的.literal_eval()是唯一安全的选项吗?


当前回答

Python在求值时很热心,所以eval(input(…))(Python 3)会在用户输入到达eval时立即求值,不管你之后对数据做了什么。因此,这是不安全的,特别是在对用户输入求值时。

使用ast.literal_eval。


举个例子,在提示符下输入这个可能对你非常不利:

__import__('os').system('rm -rf /a-path-you-really-care-about')

其他回答

ast.literal_eval()只考虑Python语法的一小部分是有效的:

提供的字符串或节点只能由以下Python文字结构组成:字符串、字节、数字、元组、列表、字典、集、布尔值和None。

通过__import__(“操作系统”)。System ('rm -rf /a-path-you-really-care-about')转换为ast.literal_eval()将引发一个错误,但eval()将很高兴地删除您的文件。

因为看起来你只是让用户输入一个普通的字典,所以使用ast.literal_eval()。它安全地做你想做的事,仅此而已。

datamap = eval(input('在这里提供一些数据:)))意味着你在判断代码是否不安全之前实际评估了代码。一旦函数被调用,它就对代码求值。另见eval的危险。

ast.literal_eval在输入不是有效的Python数据类型时引发异常,因此如果不是,代码将不会执行。

在需要eval时使用ast.literal_eval。通常不应该计算Python语句的字面值。

Python在求值时很热心,所以eval(input(…))(Python 3)会在用户输入到达eval时立即求值,不管你之后对数据做了什么。因此,这是不安全的,特别是在对用户输入求值时。

使用ast.literal_eval。


举个例子,在提示符下输入这个可能对你非常不利:

__import__('os').system('rm -rf /a-path-you-really-care-about')

eval: This is very powerful, but is also very dangerous if you accept strings to evaluate from untrusted input. Suppose the string being evaluated is "os.system('rm -rf /')" ? It will really start deleting all the files on your computer. ast.literal_eval: Safely evaluate an expression node or a string containing a Python literal or container display. The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, None, bytes and sets. Syntax:

eval(expression, globals=None, locals=None)
import ast
ast.literal_eval(node_or_string)

例子:

# python 2.x - doesn't accept operators in string format
import ast
ast.literal_eval('[1, 2, 3]')  # output: [1, 2, 3]
ast.literal_eval('1+1') # output: ValueError: malformed string


# python 3.0 -3.6
import ast
ast.literal_eval("1+1") # output : 2
ast.literal_eval("{'a': 2, 'b': 3, 3:'xyz'}") # output : {'a': 2, 'b': 3, 3:'xyz'}
# type dictionary
ast.literal_eval("",{}) # output : Syntax Error required only one parameter
ast.literal_eval("__import__('os').system('rm -rf /')") # output : error

eval("__import__('os').system('rm -rf /')") 
# output : start deleting all the files on your computer.
# restricting using global and local variables
eval("__import__('os').system('rm -rf /')",{'__builtins__':{}},{})
# output : Error due to blocked imports by passing  '__builtins__':{} in global

# But still eval is not safe. we can access and break the code as given below
s = """
(lambda fc=(
lambda n: [
    c for c in 
        ().__class__.__bases__[0].__subclasses__() 
        if c.__name__ == n
    ][0]
):
fc("function")(
    fc("code")(
        0,0,0,0,"KABOOM",(),(),(),"","",0,""
    ),{}
)()
)()
"""
eval(s, {'__builtins__':{}})

在上面的代码中().__class__. .__bases__[0] nothing but object本身。 现在我们实例化了所有的子类,这里我们的主要输入代码目标是从中找到一个名为n的类。

我们需要从实例化的子类中编写对象和函数对象。这是CPython访问object的子类并附加系统的另一种方法。

从python 3.7开始,ast.literal_eval()现在更加严格。不再允许对任意数字进行加减法运算。链接

如果您所需要的只是一个用户提供的字典,可能更好的解决方案是json.loads。主要的限制是JSON字典(“对象”)需要字符串键。你也只能提供文字数据,但ast.literal_eval也是如此。