使用python';s eval()与ast.literal_eval()的比较?

使用python';s eval()与ast.literal_eval()的比较?,python,eval,abstract-syntax-tree,Python,Eval,Abstract Syntax Tree,我遇到过这样一种情况:一些代码中出现了eval()作为可能的解决方案。现在,我以前从未使用过eval(),但是,我遇到了大量关于它可能导致的潜在危险的信息。也就是说,我对使用它非常谨慎 我的情况是,我的输入由用户提供: datamap = input('Provide some data here: ') 其中,datamap需要是一个字典。我四处搜索,发现eval()可以解决这个问题。我认为在尝试使用数据之前,我可能能够检查输入的类型,这将是一个可行的安全预防措施 datamap = eva

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

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

datamap = input('Provide some data here: ')
其中,
datamap
需要是一个字典。我四处搜索,发现
eval()
可以解决这个问题。我认为在尝试使用数据之前,我可能能够检查输入的类型,这将是一个可行的安全预防措施

datamap = eval(input('Provide some data here: ')
if not isinstance(datamap, dict):
    return
我仔细阅读了文件,我仍然不清楚这是否安全。eval是在输入数据后还是在调用
datamap
变量后立即对数据进行评估

ast
模块的
.literal\u eval()
是唯一安全的选项吗?

Python对其求值非常热心,因此
eval(input(…)
(Python 3)将在用户的输入点击
eval
时立即求值,而不管您随后对数据做了什么。因此,这是不安全的,尤其是当您评估用户输入时

使用
ast.literal\u eval


例如,在提示下输入此项可能对您非常不利:

__import__('os').system('rm -rf /a-path-you-really-care-about')
datamap=eval(input('Provide some data here:'))
意味着您在认为代码是否不安全之前实际评估了它。它会在调用函数后立即计算代码。另见

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

需要时使用
ast.literal\u eval
。您通常不应该计算字面Python语句。

只认为Python语法的一小部分是有效的:

提供的字符串或节点只能由以下Python文本结构组成:字符串、字节、数字、元组、列表、dicts、set、boolean和
None

\uuuu import\uuuu('os').system('rm-rf/a-path-you-really-care-about')
传递到
ast.literal\u eval()
将引发错误,但会很高兴地删除您的文件

因为看起来您只允许用户输入普通字典,所以请使用
ast.literal\u eval()
。它可以安全地执行您想要的操作,仅此而已。

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

ast.literal\u eval: 安全地计算表达式节点或包含Python文本或容器显示的字符串。提供的字符串或节点只能由以下Python文本结构组成:字符串、字节、数字、元组、列表、dicts、set、boolean、None、bytes和set。

语法:

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

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__':{}})
在上面的代码中,
()。\uuuuu类\uuuuu基\uuuu[0]
除了对象本身什么都没有。 现在我们实例化了所有的子类,这里我们的主要
输入代码
目标是从中找到一个名为n的类

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


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

如果您只需要一个用户提供的字典,那么更好的解决方案可能是
json.loads
。主要限制是json dict需要字符串键。另外,您只能提供文字数据,但对于
literal\u eval

来说,情况也是如此,我一直使用
ast.literal\u eval()
。我在IntellijIDEA调试器中尝试了它,调试器输出时它不断返回
None

但后来我把它的输出赋给一个变量,并用代码打印出来。它工作得很好。共享代码示例:

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

它的python版本3.6。

我正在使用python 2.7,我刚刚检查了它在python 3.x上的工作情况。糟糕的是,我一直在Python2.7
ast上尝试它。literal_-eval(“1+1”)
在Python3.7中不起作用,正如前面所说,literal_-eval应该仅限于这几个数据结构的文本。它应该无法解析二进制操作。请解释一下您的
KABOOM
代码好吗?在这里找到:@winklerr
KABOOM
在这里得到了很好的解释:这不是100%正确的建议,因为任何按位运算符(或重载运算符)都会失败。例如,
ast.literal\u eval(“1&1”)
会抛出错误,但
eval(“1&1”)
不会。只是好奇而已。如果我们期望像“1&1”这样的东西,我们不应该使用表达式解析器或其他东西吗;您将无法使用
ast.literal\u eval
进行类似的操作(例如,您可以手动实现解析器)。