eval() 极度危险,会执行任意代码;ast.literal_eval() 仅安全解析字面量,不支持运算、函数调用或属性访问,且输入必须严格符合Python字面量语法。

eval() 会直接执行任意 Python 代码,不只是“算个数”
它不是解析器,是运行时编译器:收到字符串后,立刻做词法分析 → 语法解析 → AST 构建 → 字节码生成 → 执行。整个流程跳过所有编译期优化,且默认共享当前作用域——__builtins__、globals()、甚至 type().__subclasses__() 全部可触达。
常见错误现象:eval("{'a': 1 + 2}") 看似安全,但用户传入 "__import__('os').system('id')" 时,进程已执行系统命令;删掉 __builtins__ 也不顶用,攻击者可用 ().__class__.__mro__[1].__subclasses__() 挖出 os 模块。
- 输入来源不可信(如
request.args.get('expr')、input()、文件读取)→ 几乎必然失守 - 即使加了
try/except,也拦不住静默执行——SecurityError不是默认行为,多数时候它就 quietly 成功了 - 本地测试通过 ≠ 上线安全:你本机没权限删文件,不代表服务器上不能
ast.literal_eval() 并非 “eval 的安全开关”,而是完全不同的东西
ast.literal_eval() 只认静态字面量:整数、浮点、字符串(必须带引号)、列表、元组、字典、None、True、False。它不求值、不调用函数、不访问属性、不支持运算符。
能过的:"[1, 'x', {'y': True}]"、"(1, 2)"、"b'hello'"(新版本)
必报 ValueError 的:"1.5 * 2"、"a"(单字符无引号)、"[1, 2,]"(尾部逗号)、"# comment"(注释)、JSON 格式(true / null 需先转成 True / None)
- 异常类型变了:
eval()抛SyntaxError或NameError;ast.literal_eval()只抛ValueError - 别指望它做计算——需要算术表达式,请用
simpleeval,并显式传names={"x": 5},绝不传globals() - 输入格式必须是合法 Python 字面量,不是 JSON;很多翻车发生在配置加载或 API 入参场景里,比如前端传
{"data": "[1,2,3]"},后端直接ast.literal_eval(data)却忘了外层 JSON 已解包
限制 globals/locals 是伪安全,绝大多数沙箱都已被绕过
手动删 __builtins__、只留 math、加白名单——这些操作在 CTF 和真实漏洞利用中早被反复击穿。Python 的类型系统和反射机制太强,仅靠字典过滤无法阻断路径。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
典型绕过链:().__class__.__mro__[1].__subclasses__() → 找到 os._wrap_close 或 codecs.IncrementalEncoder → 获取 os → 调用 system。整个过程不依赖任何被删掉的 built-in 函数。
- 不要自己写“安全 eval”——没人比 CPython 核心开发者更懂怎么封死所有反射入口
- 如果业务真需要动态公式计算(如风控规则引擎),用专用库如
simpleeval、numexpr,它们在 AST 层做过滤,而非靠运行时字典拦截 - 配置文件里写
"[1, 2, 3] + [4]"?eval()会算,ast.literal_eval()直接报错——这恰恰是安全边界的体现,不是缺陷
真正容易被忽略的点:输入来源 + 异常处理 + 格式契约
很多人换掉 eval() 后仍出问题,不是因为 ast.literal_eval() 不够好,而是没意识到三件事:
- 输入必须是合法 Python 字面量,不是 JSON、不是用户随手敲的“1,2,3”、不是带空格或换行的脏数据
- 异常处理逻辑要重写:
ValueError不代表“用户输错了”,可能意味着恶意构造(比如尝试注入__import__但被字面量解析器提前截断) - 单字符字符串如
"a"必须带引号;尾部逗号、注释、十六进制字面量(0xFF)在旧版 Python 中也不支持——这些细节在 API 入参或配置加载时极易翻车
最危险的,是那种“看着过了测试、上线后某天突然崩掉”的情况:输入格式微小变化,触发了未覆盖的边界路径,而你连日志里都看不到明显的报错。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










