Python eval函数执行动态表达式详解与安全风险

月亮慢半拍
月亮慢半拍
发布时间:2026-10-11 | 3人浏览过
原创

eval函数是Python中用于执行动态表达式的重要工具,但其执行机制涉及全局与局部命名空间的复杂交互。本文深入解析eval的参数行为,展示如何通过控制globals和locals来限制变量访问,并重点讨论通过禁用内置函数来降低安全风险的操作方法。

eval函数的基本机制

eval函数的核心作用是将字符串解析为Python表达式并返回求值结果。其函数签名为 eval(expression, globals=None, locals=None)。其中,expression 参数必须是合法的Python表达式字符串,而非语句。若表达式存在语法错误,函数将抛出异常。

该函数支持执行由 compile() 创建的代码对象。需要注意的是,如果代码对象是以 'exec' 模式编译的,eval 将返回 None,因为 exec 模式通常用于执行语句而非表达式。

命名空间控制:globals 与 locals

eval 的执行环境由 globals 和 locals 两个参数共同决定。理解这两个参数的行为对于安全使用 eval 至关重要。

参数类型与默认行为

  • globals 参数必须是字典类型(dict)。
  • locals 参数可以是任意映射对象(mapping object)。
  • 若两者均省略,eval 将在调用时的当前环境中执行,即使用当前的全局和局部命名空间。
  • 若 globals 存在但缺少 __builtins__ 键,Python 会自动复制当前全局变量中的 __builtins__ 引用。
  • 若 locals 被省略,其默认值即为 globals 字典。

作用域隔离示例

通过显式传递字典,可以限制 eval 访问的变量范围。以下示例展示了如何仅暴露特定变量:

>>> g = {'num': 2}
>>> eval('num + 2') # 错误:num 未定义
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    eval('num + 2')
  File "<string>", line 1, in <module>
NameError: name 'num' is not defined

>>> eval('num + 2', g) # 正确:g 中定义了 num
4

当需要同时访问全局和局部变量时,可以分别传递两个字典。全局变量在 globals 中查找,局部变量在 locals 中查找:

>>> g = {'num1': 2}
>>> l = {'num2': 4}
>>> eval('num1 + num2', g, l)
6

默认行为与 locals 的陷阱

当 globals 为空字典且未提供 locals 时,Python 的行为可能出乎意料。此时 locals 默认为 globals(即空字典),导致当前环境中的变量无法被访问:

>>> num = 1
>>> eval('num + 2', {}) # 错误:locals 默认为 {},找不到 num
Traceback (most recent call last):
  File "<pyshell#3>", line 1, in <module>
    eval('num + 2', {})
  File "<string>", line 1, in <module>
NameError: name 'num' is not defined

若希望访问当前局部变量,需显式获取 locals() 并传入:

>>> l = locals()
>>> eval('num + 2', {}, l) # 正确:从 l 中找到 num
3

安全风险与限制措施

eval 函数执行任意代码的能力带来了严重的安全风险。攻击者可能通过构造恶意表达式访问敏感数据或执行系统命令。因此,在生产环境中应严格限制 eval 的执行环境。

禁用内置函数

Python 自动在 globals 中添加 __builtins__ 引用,使得 eval 可以访问所有内置函数(如 abs, open, exec 等)。为了限制这种能力,可以手动将 __builtins__ 设置为空字典:

>>> g = {}
>>> eval('abs(-1)', g)
1
>>> g = {'__builtins__': {}}
>>> eval('abs(-1)', g) # 错误:无法使用内置函数
Traceback (most recent call last):
  File "<pyshell#9>", line 1, in <module>
    eval('abs(-1)', g)
  File "<string>", line 1, in <module>
NameError: name 'abs' is not defined

通过这种方式,可以大幅降低 eval 被滥用的风险。然而,这并不能完全消除所有安全风险,因为仍可能通过其他途径访问受限资源。

安全替代方案

对于仅包含字面量(如数字、字符串、列表、字典等)的表达式,建议使用 ast.literal_eval()。该函数仅评估安全的字面量结构,不会执行任意代码,从而避免了 eval 的安全隐患:

>>> import ast
>>> ast.literal_eval('[1, 2, 3]')
[1, 2, 3]

总结

eval 函数提供了强大的动态表达式执行能力,但其对命名空间的控制需要谨慎处理。通过合理设置 globals 和 locals,可以限制变量的访问范围。同时,务必注意安全风险,通过禁用 __builtins__ 或使用 ast.literal_eval() 来确保代码执行的安全性。

以上就是Python使用eval函数执行动态表达式过程的详细内容,更多关于Python eval函数安全使用的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表