使用python的eval()与ast.literal_eval()?

问题:使用python的eval()与ast.literal_eval()?

我遇到了一些代码,eval()将其作为一种可能的解决方案。现在,我以前从未使用eval()过,但是,我遇到了很多有关它可能引起的潜在危险的信息。也就是说,我对使用它非常谨慎。

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

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

哪里datamap需要一本字典。我四处搜寻,发现eval()可以解决这个问题。我认为我可以在尝试使用数据之前检查输入的类型,这将是可行的安全预防措施。

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

我通读了文档,但仍不清楚这是否安全。eval是否在输入数据后或datamap调用变量后立即评估数据?

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

I have a situation with some code where eval() came up as a possible solution. Now I have never had to use eval() before but, I have come across plenty of information about the potential danger it can cause. That said, I’m very wary about using it.

My situation is that I have input being given by a user:

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

Where datamap needs to be a dictionary. I searched around and found that eval() could work this out. I thought that I might be able to check the type of the input before trying to use the data and that would be a viable security precaution.

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

I read through the docs and I am still unclear if this would be safe or not. Does eval evaluate the data as soon as its entered or after the datamap variable is called?

Is the ast module’s .literal_eval() the only safe option?


回答 0

datamap = eval(raw_input('Provide some data here: '))意味着您实际上认为代码不安全之前对其进行了评估。调用该函数后,它将立即评估代码。另请参阅的危险eval

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

使用ast.literal_eval时,你需要eval。通常,您不应该评估文字Python语句。

datamap = eval(input('Provide some data here: ')) means that you actually evaluate the code before you deem it to be unsafe or not. It evaluates the code as soon as the function is called. See also the dangers of eval.

ast.literal_eval raises an exception if the input isn’t a valid Python datatype, so the code won’t be executed if it’s not.

Use ast.literal_eval whenever you need eval. You shouldn’t usually evaluate literal Python statements.


回答 1

ast.literal_eval() 仅认为Python语法的一小部分有效:

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

传递__import__('os').system('rm -rf /a-path-you-really-care-about')ast.literal_eval()将引发一个错误,但eval()会愉快地擦拭您的驱动器。

由于看起来您只是让用户输入普通字典,所以请使用ast.literal_eval()。它可以安全地执行您想要的操作,仅此而已。

ast.literal_eval() only considers a small subset of Python’s syntax to be valid:

The string or node provided may only consist of the following Python literal structures: strings, bytes, numbers, tuples, lists, dicts, sets, booleans, and None.

Passing __import__('os').system('rm -rf /a-path-you-really-care-about') into ast.literal_eval() will raise an error, but eval() will happily delete your files.

Since it looks like you’re only letting the user input a plain dictionary, use ast.literal_eval(). It safely does what you want and nothing more.


回答 2

eval: 此功能非常强大,但是如果您接受字符串以从不受信任的输入中求值,则也非常危险。假设要评估的字符串是“ os.system(’rm -rf /’)”?它将真正开始删除计算机上的所有文件。

ast.literal_eval: 安全地评估表达式节点或包含Python文字或容器显示的字符串。提供的字符串或节点只能由以下Python文字结构组成:字符串,字节,数字,元组,列表,字典,集合,布尔值,无,字节和集合。

句法:

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],对象本身就是什么。现在我们实例化了所有子类,这里我们的主要enter code here目标是从中找到一个名为n的类。

我们需要code对象和function实例化的子类的对象。这是CPython访问对象子类并附加系统的另一种方法。

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

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)

Example:

# 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__':{}})

In the above code ().__class__.__bases__[0] nothing but object itself. Now we instantiated all the subclasses, here our main enter code hereobjective is to find one class named n from it.

We need to code object and function object from instantiated subclasses. This is an alternative way from CPython to access subclasses of object and attach the system.

From python 3.7 ast.literal_eval() is now stricter. Addition and subtraction of arbitrary numbers are no longer allowed. link


回答 3

Python 渴望进行评估,因此无论eval(raw_input(...))用户eval随后对数据进行什么操作,只要它点击,就将评估用户的输入。因此,这是不安全的,尤其是在eval用户输入时。

使用ast.literal_eval


例如,在提示符下输入此命令对您非常不利:

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

Python’s eager in its evaluation, so eval(input(...)) (Python 3) will evaluate the user’s input as soon as it hits the eval, regardless of what you do with the data afterwards. Therefore, this is not safe, especially when you eval user input.

Use ast.literal_eval.


As an example, entering this at the prompt could be very bad for you:

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

回答 4

如果您需要的只是用户提供的词典,则可能是更好的解决方案json.loads。主要限制是json dict需要字符串键。另外,您只能提供文字数据,但情况也是如此literal_eval

If all you need is a user provided dictionary, possible better solution is json.loads. The main limitation is that json dicts requires string keys. Also you can only provide literal data, but that is also the case for literal_eval.


回答 5

我被困住了ast.literal_eval()。我在IntelliJ IDEA调试器中尝试过它,并一直None在调试器输出中返回。

但是稍后,当我将其输出分配给变量并以代码打印时。工作正常。共享代码示例:

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

其python版本3.6。

I was stuck with ast.literal_eval(). I was trying it in IntelliJ IDEA debugger, and it kept returning None on debugger output.

But later when I assigned its output to a variable and printed it in code. It worked fine. Sharing code example:

import ast
sample_string = '[{"id":"XYZ_GTTC_TYR", "name":"Suction"}]'
output_value = ast.literal_eval(sample_string)
print(output_value)

Its python version 3.6.