Python 中安全地对用户提交代码进行动态跟踪与调试的完整实践指南

夏晨大大_3785

夏晨大大_3785

2026-11-03

736人浏览

原创

Python 中安全地对用户提交代码进行动态跟踪与调试的完整实践指南

本文介绍如何在不使用危险的 eval 或 exec 的前提下,对任意 Python 源码字符串(如用户提交的函数定义)进行安全的运行时跟踪,通过 AST 解析、字节码注入或 compile() + exec() 配合沙箱化上下文实现可控 tracing。

本文介绍如何在不使用危险的 `eval` 或 `exec` 的前提下,对任意 python 源码字符串(如用户提交的函数定义)进行安全的运行时跟踪,通过 ast 解析、字节码注入或 `compile()` + `exec()` 配合沙箱化上下文实现可控 tracing。

要对用户提交的 Python 代码(例如一段包含 def adder(x, y): return x + y 的源码字符串)实现精确的运行时变量追踪(如记录每次赋值、调用、返回),绝不能直接使用 eval() 或裸 exec()——正如提问者所警觉的,这会带来严重的代码注入与权限越界风险。

正确的路径是:将源码安全编译为代码对象 → 在受控命名空间中执行 → 结合 sys.settrace() 实现细粒度跟踪。关键在于隔离执行环境,并避免全局污染。

Python Pep Authoring
Python Pep Authoring

依据官方 python/peps仓库规则起草、审阅、编辑或准备 Python 改进提案(PEP),用于处理 PEP 文本和元数据头部。

下载

✅ 推荐方案:compile() + 安全 exec() + sys.settrace

import sys
import ast
import functools

def trace_calls(frame, event, arg):
    if event == 'line':
        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        print(f"[TRACE] {filename}:{lineno} | locals: {dict(frame.f_locals)}")
    elif event == 'call':
        func_name = frame.f_code.co_name
        print(f"[CALL] → {func_name}")
    elif event == 'return':
        print(f"[RETURN] ← {arg}")
    return trace_calls  # 继续跟踪

def safe_trace_source(source_code: str, global_ns: dict = None) -> dict:
    """
    安全执行并跟踪用户提供的 Python 源码字符串
    返回执行后的局部变量快照(不含内置/危险模块)
    """
    # 1. 静态验证:初步 AST 检查(可选增强安全)
    try:
        tree = ast.parse(source_code)
        # 禁止危险节点(示例:禁止 import、open、__import__ 调用)
        for node in ast.walk(tree):
            if isinstance(node, (ast.Import, ast.ImportFrom)):
                raise ValueError("Import statements are not allowed.")
            if isinstance(node, ast.Call):
                if (isinstance(node.func, ast.Name) and 
                    node.func.id in ('exec', 'eval', '__import__', 'open')):
                    raise ValueError(f"Disallowed call: {node.func.id}")
    except SyntaxError as e:
        raise ValueError(f"Invalid Python syntax: {e}")

    # 2. 编译为 code object(指定 filename 便于 trace 定位)
    code = compile(source_code, filename="<user_input>", mode="exec")

    # 3. 构建最小、受限的执行环境
    safe_globals = {
        '__builtins__': {
            'print': print,
            'len': len,
            'range': range,
            'list': list,
            'dict': dict,
            'int': int,
            'float': float,
            'str': str,
            # ⚠️ 显式排除危险内置:open, exec, eval, __import__, etc.
        }
    }
    if global_ns:
        safe_globals.update(global_ns)

    local_ns = {}

    # 4. 启用跟踪并执行
    sys.settrace(trace_calls)
    try:
        exec(code, safe_globals, local_ns)
    finally:
        sys.settrace(None)  # 必须确保清除 trace,避免影响后续代码

    return local_ns

# 使用示例
user_code = """
def adder(x, y):
    z = x + y
    return z

result = adder(3, 5)
"""

print("=== 开始跟踪用户代码 ===")
namespace = safe_trace_source(user_code)
print("执行后局部变量:", namespace)  # {'adder': <function>, 'result': 8}</function></user_input>

? 关键注意事项

  • compile() 是安全起点:它只做语法解析和编译,不执行,无副作用;相比 eval()/exec() 字符串直调,可控性高得多。
  • sys.settrace() 作用域精准:它仅对当前线程中 exec() 执行的代码生效,不会污染主程序逻辑。
  • 命名空间隔离是核心防线:通过显式传入 safe_globals 并剔除危险内置,从根本上阻断文件读写、系统调用等攻击面。
  • AST 预检可进一步加固:如需更高安全等级(如教育平台、编程题库),可在 compile 前遍历 AST 过滤 subprocess, os.system, ctypes 等敏感操作。
  • 不要在生产环境启用 sys.settrace() 全局长期监听:性能损耗显著(每行/每调用触发),应严格限定在单次 exec 生命周期内。

✅ 替代进阶方案(按安全性升序)

方案 安全性 适用场景 简要说明
compile() + 受限 exec() ★★★☆☆ 通用教学/调试 如上所示,平衡安全与灵活性
ast.NodeTransformer + 动态重写 ★★★★☆ 需插桩日志/计时 修改 AST 插入 print() 或计数器,再 compile()
bytecode 库(如 bytecode 或 dis 分析+patch) ★★★★★ 高级性能分析 直接操作字节码,完全绕过源码解释风险,但复杂度高

? 总结:对用户代码做 tracing 的本质,不是“如何执行字符串”,而是“如何在沙箱中安全加载、监控并卸载一段逻辑”。抛弃 eval,拥抱 compile + 环境隔离 + sys.settrace,是你构建可信赖 Python 代码分析工具的坚实基础。

Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

python 字节 python函数

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

2023.07.20

1851

4

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

2023.07.25

5044

7

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

2023.07.31

1809

3

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

2023.08.03

30297

23

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3607

5

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.04

3607

5

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

1243

5

python合并两个列表
python合并两个列表

Python是一种强大的编程语言,具有许多方便的功能和工具。在Python中,有多种方法可以合并两个列表。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

2023.08.10

616

4

python是前端还是后端
python是前端还是后端

Python属于前端也属于后端,其灵活性和丰富的生态系统使得开发人员能够在不同的领域中灵活运用。本专题为大家提供python相关的文章、下载、课程内容,供大家免费下载体验。

2023.08.11

2803

5

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程