深入理解 Python 的 eval() 函数与空全局字典 {}

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: `eval()` 函数在 Python 中能将字符串解析为代码并执行,但伴随安全风险,尤其在处理不受信任的输入时。传递空全局字典 {} 可限制其访问内置对象,但仍存隐患。建议通过限制函数和变量、使用沙箱环境、避免复杂表达式、验证输入等提高安全性。更推荐使用 `ast.literal_eval()`、自定义解析器或 JSON 解析等替代方案,以确保代码安全性和可靠性。

在Python编程中,eval() 函数是一个强大但常被误解的工具。它能够将字符串表达式解析为Python代码并执行,返回表达式的结果。然而,eval() 的使用伴随着安全风险,特别是在处理不受信任的输入时。为了安全地使用 eval(),了解其参数,特别是全局字典 {} 的作用,至关重要。本文将通过简洁的语言、清晰的逻辑和实际的代码案例,带你深入理解 eval() 函数与空全局字典 {} 的工作机制。站大爷代理IP工具的验证功能介绍 (6).png

一、eval() 函数基础
eval() 函数的基本语法如下:

eval(expression, globals=None, locals=None)

expression:一个字符串表达式,eval() 会将其解析并执行。
globals:可选参数,指定全局命名空间。如果省略,则使用调用者的全局命名空间。
locals:可选参数,指定局部命名空间。如果省略,则使用调用者的局部命名空间。
二、全局字典 {} 的作用
在 eval() 函数中,全局字典 {} 用于定义表达式执行时的全局命名空间。当你传递一个空字典 {} 作为 globals 参数时,你实际上是在创建一个隔离的全局命名空间,其中不包含任何内置的Python对象或函数。这意味着,除非你在这个字典中显式地定义它们,否则 eval() 中的表达式将无法访问任何内置的Python功能。

案例1:无全局字典

不传递 globals 参数

result = eval('2 + 2')
print(result) # 输出: 4

在这个例子中,eval() 能够访问内置的加法运算符,因为使用了调用者的全局命名空间。

案例2:空全局字典

传递空字典作为 globals 参数

result = eval('2 + 2', {})
print(result) # 报错: NameError: name '+' is not defined

在这个例子中,由于传递了空字典,eval() 无法找到内置的加法运算符,因此报错。

三、为什么使用空全局字典 {} 可能不安全?
虽然使用空全局字典 {} 可以限制 eval() 访问全局命名空间中的内置对象,但这并不意味着它是安全的。实际上,这种限制可能会引发一些意想不到的问题,甚至可能被恶意利用。

案例3:绕过空全局字典的限制

尝试在空全局字典中执行复杂表达式

code = """
def inner_func():
return 'Hello, World!'
inner_func()
"""
result = eval(code, {})
print(result) # 报错: NameError: name 'def' is not defined

在这个例子中,由于空全局字典的限制,eval() 无法识别 def 关键字,因此报错。然而,这并不意味着不能绕过这种限制。恶意用户可能会利用其他方式(如字符串拼接、编码等)来构造能够绕过这些限制的表达式。

更重要的是,即使你限制了全局命名空间,eval() 仍然可以访问传递给它的局部命名空间(如果提供了 locals 参数)。这意味着,如果 locals 参数包含敏感信息或可执行代码,那么这些信息或代码仍然可能被恶意利用。

四、更安全地使用 eval()
由于 eval() 的潜在安全风险,通常建议避免使用它,特别是在处理不受信任的输入时。然而,在某些情况下,如果你确实需要使用 eval(),以下是一些提高安全性的建议:

限制可用的函数和变量:通过仔细选择 globals 和 locals 参数中的内容,限制 eval() 可以访问的函数和变量。
使用沙箱环境:考虑使用第三方库(如 restrictedpython)来创建一个受限的Python沙箱环境,在其中执行不受信任的代码。
避免执行复杂表达式:尽量避免在 eval() 中执行复杂的表达式或代码块。如果可能的话,将代码分解为更小的、更易于管理的部分,并分别处理它们。
输入验证和消毒:在将输入传递给 eval() 之前,对其进行严格的验证和消毒。确保输入只包含预期的字符和格式。
日志记录和监控:对 eval() 的使用进行日志记录和监控。这有助于检测任何潜在的安全问题或异常行为。
五、替代方案
在许多情况下,可以使用其他更安全的方法来替代 eval()。例如:

使用 ast.literal_eval():这个函数只能安全地评估一个表达式,该表达式产生一个Python字面量结构(如数字、字符串、列表、元组、字典和集合)。它不允许执行任意的代码或访问内置的Python对象。

import ast

安全地评估一个字面量表达式

result = ast.literal_eval('[1, 2, 3]')
print(result) # 输出: [1, 2, 3]

使用自定义解析器:根据你的需求设计一个自定义的解析器来处理特定的输入格式。这种方法可以提供更高的安全性和灵活性。
使用JSON:如果你的输入数据是结构化的(如JSON格式),那么可以考虑使用Python的内置 json 模块来解析和处理这些数据。这种方法比 eval() 更安全,因为它只支持JSON格式的数据。

import json

解析JSON格式的字符串

data = '{"name": "Alice", "age": 30}'
result = json.loads(data)
print(result) # 输出: {'name': 'Alice', 'age': 30}

六、总结
eval() 函数在Python中是一个强大但危险的工具。了解并谨慎使用其参数,特别是全局字典 {},对于确保代码的安全性至关重要。然而,由于 eval() 的潜在安全风险,通常建议避免使用它,特别是在处理不受信任的输入时。相反,可以考虑使用其他更安全的方法来替代 eval(),如 ast.literal_eval()、自定义解析器或JSON解析等。通过这些方法,你可以更安全地处理输入数据,并降低潜在的安全风险。

目录
相关文章
|
1月前
|
Python
[oeasy]python057_如何删除print函数_dunder_builtins_系统内建模块
本文介绍了如何删除Python中的`print`函数,并探讨了系统内建模块`__builtins__`的作用。主要内容包括: 1. **回忆上次内容**:上次提到使用下划线避免命名冲突。 2. **双下划线变量**:解释了双下划线(如`__name__`、`__doc__`、`__builtins__`)是系统定义的标识符,具有特殊含义。
30 3
|
26天前
|
存储 人工智能 Python
[oeasy]python061_如何接收输入_input函数_字符串_str_容器_ 输入输出
本文介绍了Python中如何使用`input()`函数接收用户输入。`input()`函数可以从标准输入流获取字符串,并将其赋值给变量。通过键盘输入的值可以实时赋予变量,实现动态输入。为了更好地理解其用法,文中通过实例演示了如何接收用户输入并存储在变量中,还介绍了`input()`函数的参数`prompt`,用于提供输入提示信息。最后总结了`input()`函数的核心功能及其应用场景。更多内容可参考蓝桥、GitHub和Gitee上的相关教程。
14 0
|
2月前
|
Python
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
Python中的函数是**一种命名的代码块,用于执行特定任务或计算
63 18
|
2月前
|
数据可视化 DataX Python
Seaborn 教程-绘图函数
Seaborn 教程-绘图函数
83 8
|
2月前
|
Python
Python中的函数
Python中的函数
60 8
|
9月前
|
存储 Python
python字典中删除键值的方法
python字典中删除键值的方法
185 0
|
Python
python知识点100篇系列(8)-字典去重复的几种方法
python知识点100篇系列(8)-字典去重复的几种方法
344 1
|
9月前
|
存储 JSON JavaScript
Python字典和JSON字符串相互转化方法
【2月更文挑战第18天】
254 3
|
5月前
|
关系型数据库 MySQL 数据库
Python MySQL查询返回字典类型数据的方法
通过使用 `mysql-connector-python`库并选择 `MySQLCursorDict`作为游标类型,您可以轻松地将MySQL查询结果以字典类型返回。这种方式提高了代码的可读性,使得数据操作更加直观和方便。上述步骤和示例代码展示了如何实现这一功能,希望对您的项目开发有所帮助。
203 4
|
6月前
|
存储 Python 容器
python字典的常用操作方法
python字典的常用操作方法