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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15197673/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 19:29:24  来源:igfitidea点击:

Using python's eval() vs. ast.literal_eval()?

pythonevalabstract-syntax-tree

提问by tijko

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.

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

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

我的情况是我有用户提供的输入:

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

Where datamapneeds 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()可以解决这个问题。我认为我可以在尝试使用数据之前检查输入的类型,这将是一种可行的安全预防措施。

datamap = eval(raw_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 datamapvariable is called?

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

Is the astmodule's .literal_eval()the only safe option?

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

采纳答案by Volatility

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

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

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

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

Use ast.literal_evalwhenever you need eval. You shouldn't usually evaluate literal Python statements.

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

回答by nneonneo

Python's eagerin its evaluation, so eval(raw_input(...))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 evaluser input.

Python急于求值,因此eval(raw_input(...))会在用户输入到达 时立即求值eval,无论您之后如何处理数据。因此,这并不安全,尤其是当您进行eval用户输入时。

Use ast.literal_eval.

使用ast.literal_eval.



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

例如,在提示符下输入这个对你来说非常非常糟糕:

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

回答by Blender

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

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

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

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

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

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

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.

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

回答by Kiran Kumar Kotari

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:这是非常强大的,但如果你接受字符串来评估不受信任的输入,这也是非常危险的。假设正在评估的字符串是 "os.system('rm -rf /')" ?它会真正开始删除您计算机上的所有文件。

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

句法:

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 nfrom it.

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

We need to codeobject and functionobject from instantiated subclasses. This is an alternative way from CPythonto access subclasses of object and attach the system.

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

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

从 python 3.7 ast.literal_eval() 现在更严格。不再允许任意数字的加减。关联

回答by Chinasaur

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.

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

回答by M Haziq

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

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

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.

它的python版本3.6。