python中的eval()被视为不安全函数的核心原因在于其能够执行任意代码,导致严重的安全风险,尤其当输入来源不可信时。①攻击者可构造恶意输入,执行如文件操作、数据泄露等危险行为;②即使尝试通过限制globals和locals参数构建“沙箱”,也难以真正安全;③推荐使用ast.literal_eval()、json.loads()等替代方案;④通过ast静态分析可有效识别eval()调用并评估其风险等级;⑤运行时应严格验证输入、限制权限并避免eval()的使用。

在Python项目中识别并处理不安全的eval()使用,核心在于理解其带来的巨大安全风险,并结合静态代码分析与必要的运行时考量。最直接有效的方法是利用Python内置的ast模块进行抽象语法树分析,辅以代码审查和对替代方案的深入理解。

要发现不安全的eval()使用,我们可以编写一个脚本来遍历项目的Python文件,解析它们的抽象语法树(AST),并查找所有对eval函数的调用。一旦找到,就需要进一步分析eval的参数来源。如果参数来源于外部不可信输入(如用户提交的数据、网络请求内容、文件读取等),或者是一个动态构建的字符串,那么这几乎可以肯定是一个安全漏洞。
一个基本的AST扫描器可以这样构建:
立即学习“Python免费学习笔记(深入)”;

import ast
import os
class EvalFinder(ast.NodeVisitor):
def __init__(self):
self.eval_calls = []
def visit_Call(self, node):
# 检查是否是函数调用
if isinstance(node.func, ast.Name) and node.func.id == 'eval':
# 找到一个eval()调用
# 进一步分析node.args[0]可以判断参数类型
# 例如,如果是ast.Str,可能是字面量字符串
# 如果是ast.Name,则参数是一个变量,需要进一步追踪其来源
self.eval_calls.append({
'line': node.lineno,
'col': node.col_offset,
'args': [ast.dump(arg) for arg in node.args] # 简单展示参数结构
})
self.generic_visit(node) # 继续遍历子节点
def find_eval_in_file(filepath):
with open(filepath, 'r', encoding='utf-8') as f:
content = f.read()
try:
tree = ast.parse(content, filename=filepath)
finder = EvalFinder()
finder.visit(tree)
return finder.eval_calls
except SyntaxError as e:
print(f"Error parsing {filepath}: {e}")
return []
def scan_project_for_eval(project_root):
all_eval_uses = {}
for root, _, files in os.walk(project_root):
for file in files:
if file.endswith('.py'):
filepath = os.path.join(root, file)
eval_uses = find_eval_in_file(filepath)
if eval_uses:
all_eval_uses[filepath] = eval_uses
return all_eval_uses
# 示例用法:
# project_path = './my_python_project'
# insecure_evals = scan_project_for_eval(project_path)
# for file, calls in insecure_evals.items():
# print(f"File: {file}")
# for call in calls:
# print(f" Line {call['line']}, Col {call['col']}: eval({call['args']})")
这个AST扫描器能定位到eval的调用点。更复杂的分析会涉及到数据流追踪,例如一个变量被eval调用,但这个变量的值是在程序运行过程中从用户输入、网络请求等外部来源获取的。这超出了纯粹静态分析的范畴,通常需要更专业的静态分析工具或人工代码审查。
eval()为何被视为不安全函数?eval()函数在Python中被认为是极其危险的,其核心原因在于它能够执行任意的Python代码。当你把一个字符串传递给eval(),Python解释器会尝试将这个字符串当作一个完整的Python表达式来求值并执行。这意味着,如果攻击者能够控制传递给eval()的字符串内容,他们就可以在你的应用程序运行环境中执行任何他们想执行的代码。

这听起来可能有点抽象,但想象一下:一个Web应用接收用户提交的查询字符串,然后直接用eval()来处理。如果用户输入的是__import__('os').system('rm -rf /'),那么你的服务器文件系统可能就遭殃了。这可不是开玩笑,而是实实在在的威胁。它不仅仅限于文件操作,还可以是数据泄露(比如读取环境变量、数据库凭证)、权限提升、甚至是在你的服务器上安装恶意软件。
很多人会误以为eval()提供了一个“沙箱”环境,或者通过限制globals和locals参数就能安全使用。但实际情况是,构建一个真正安全的Python沙箱是极其困难的,几乎不可能完美。即使限制了内置函数和全局变量,攻击者也常常能找到绕过的方法,例如通过对象的属性、方法链等来访问受限资源。所以,默认的立场应该是:除非你对输入有绝对的控制且能确保其安全性,否则永远不要使用eval()。
eval()的利器静态分析,尤其基于抽象语法树(AST)的分析,是发现代码中潜在eval()滥用的最可靠方法之一。不像正则表达式,AST分析能够真正理解代码的结构和语义,避免误报和漏报。Python的ast模块正是为此而生。
当我们用ast.parse()将Python源代码转换为AST时,我们得到的是一个树形结构,每个节点代表了代码中的一个元素,比如一个函数调用、一个变量赋值、一个循环等等。对于eval()的检测,我们关注的是ast.Call节点,它表示一个函数调用。通过遍历这棵树,我们可以很容易地识别出所有名为eval的函数调用。
但仅仅找到eval还不够。一个字面量字符串,比如eval("1 + 1"),虽然使用了eval,但其风险是可控的,因为代码内容是固定的。真正危险的是当eval的参数是变量,或者是一个从外部输入动态构建的字符串时。虽然AST本身无法追踪变量在运行时的具体值,但它可以识别出参数的类型。如果eval的参数不是一个简单的字面量字符串(ast.Str),而是一个变量(ast.Name)、一个函数调用(ast.Call)、一个二进制操作(ast.BinOp)等,那么这就需要引起高度警惕了。
例如,在上面的EvalFinder中,我们捕获了eval的调用及其参数的AST表示。这提供了一个起点,让你能够手动审查这些调用,或者在此基础上构建更复杂的数据流分析,尝试追踪变量的来源。对于大型项目,这样的AST扫描器能快速提供一个“危险清单”,大大提高代码审计的效率。当然,它也有局限性,比如无法处理通过getattr、__builtins__等方式动态构造的eval调用,以及无法在编译时确定变量的实际值。
发现代码中的eval()使用只是第一步,更重要的是如何处理它们,以及在无法避免时如何进行运行时防御。理想情况下,如果发现不安全的eval(),应该立即将其替换掉。
替换eval()的常见安全替代方案:
json.loads() 或 yaml.safe_load(): 如果你只是想解析JSON或YAML格式的数据,这些是安全且专用的方法。它们不会执行任意代码。ast.literal_eval(): 如果你需要安全地评估只包含Python字面量(字符串、数字、元组、列表、字典、布尔值和None)的表达式,ast.literal_eval()是完美的选择。它会拒绝任何非字面量的表达式,从而避免代码执行。eval()。这虽然工作量大,但安全性最高。如果eval()真的不可避免(极少数情况):
globals和locals: eval()函数接受globals和locals参数,可以用来限制可用的全局和局部命名空间。例如,eval(code_str, {"__builtins__": {}}, {})可以创建一个非常受限的环境。但请注意,这并非万无一失的沙箱,经验丰富的攻击者仍可能找到绕过方法。eval()的输入进行极其严格的验证和净化,确保它只包含预期的数据或表达式,绝不包含任何可执行代码的片段。这通常意味着白名单验证,而不是黑名单(因为你永远无法穷尽所有恶意输入)。eval()被利用,也能将损害降到最低。最终,最好的防御策略是避免使用eval()。在绝大多数情况下,都有更安全、更健壮的替代方案。代码审查和开发团队的安全意识培训也至关重要,它们能从源头上减少eval()这种高风险函数的引入。
以上就是如何使用Python发现不安全的eval()使用?的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号