新闻详情

新闻详情

首页 / 资讯中心 / 详情

AST 安全求值

发布时间:2026/9/30 14:45:21来源:尧图网络
AST 安全求值
AST 安全求值指的是把表达式/代码先解析成抽象语法树AST然后不直接eval/compile执行而是自己遍历 AST只允许白名单内的节点并按预定语义解释执行。核心目标是避免任意代码执行、沙箱逃逸和拒绝服务。一句话解析成 AST 白名单解释器 资源限制 默认拒绝。1. 为什么不直接用 evalPython 的eval、JS 的eval/new Function都极其危险pythoneval(__import__(os).system(rm -rf /))即使限制__builtins__也可能通过属性链、类继承、生成器等方式逃逸。所以安全求值不能依赖“过滤字符串”而应基于 AST 白名单。2. 安全求值的基本原则默认拒绝没显式允许的 AST 节点一律报错。不调用、不导入、不访问属性禁止Call、Import、Attribute、Subscript等。变量来自受控环境只允许简单类型如int/float/str/bool/None。运算符白名单只允许 - * / // % **、比较、布尔等并限制**。资源限制输入长度、AST 节点数、递归深度、数值大小、字符串长度、执行时间。纯函数、无副作用求值不能修改外部状态。3. Python 示例安全表达式求值只允许变量、常量、四则运算、比较、布尔、三元表达式。pythonimport ast import operator as op _BIN { ast.Add: op.add, ast.Sub: op.sub, ast.Mult: op.mul, ast.Div: op.truediv, ast.FloorDiv: op.floordiv, ast.Mod: op.mod, } _UNARY { ast.UAdd: op.pos, ast.USub: op.neg, ast.Not: op.not_, } _CMP { ast.Eq: op.eq, ast.NotEq: op.ne, ast.Lt: op.lt, ast.LtE: op.le, ast.Gt: op.gt, ast.GtE: op.ge, ast.In: lambda a, b: a in b, ast.NotIn: lambda a, b: a not in b, } _ALLOWED_TYPES (int, float, str, bool, type(None)) def safe_eval(expr: str, variablesNone, max_nodes1000, max_pow100): variables variables or {} tree ast.parse(expr, modeeval) if sum(1 for _ in ast.walk(tree)) max_nodes: raise ValueError(表达式过大) return _eval(tree, variables, max_pow) def _eval(node, env, max_pow): if isinstance(node, ast.Expression): return _eval(node.body, env, max_pow) if isinstance(node, ast.Constant): if isinstance(node.value, _ALLOWED_TYPES): return node.value raise ValueError(不允许的常量) if isinstance(node, ast.Name): if node.id in env and isinstance(env[node.id], _ALLOWED_TYPES): return env[node.id] raise ValueError(f未知或不允许的变量: {node.id}) if isinstance(node, ast.BinOp): left _eval(node.left, env, max_pow) right _eval(node.right, env, max_pow) if isinstance(node.op, ast.Pow): if not isinstance(right, (int, float)) or abs(right) max_pow: raise ValueError(指数过大) if isinstance(left, (int, float)) and abs(left) 1e6: raise ValueError(底数过大) return left ** right fn _BIN.get(type(node.op)) if fn is None: raise ValueError(不允许的二元运算) # 防止字符串乘法耗尽内存 if isinstance(node.op, ast.Mult): if isinstance(left, str) and isinstance(right, int) and len(left) * right 10000: raise ValueError(字符串过长) if isinstance(right, str) and isinstance(left, int) and len(right) * left 10000: raise ValueError(字符串过长) return fn(left, right) if isinstance(node, ast.UnaryOp): fn _UNARY.get(type(node.op)) if fn is None: raise ValueError(不允许的一元运算) return fn(_eval(node.operand, env, max_pow)) if isinstance(node, ast.BoolOp): if isinstance(node.op, ast.And): result True for v in node.values: result _eval(v, env, max_pow) if not result: return result return result if isinstance(node.op, ast.Or): result False for v in node.values: result _eval(v, env, max_pow) if result: return result return result raise ValueError(不允许的布尔运算) if isinstance(node, ast.Compare): left _eval(node.left, env, max_pow) for op_node, comparator in zip(node.ops, node.comparators): right _eval(comparator, env, max_pow) fn _CMP.get(type(op_node)) if fn is None or not fn(left, right): return False left right return True if isinstance(node, ast.IfExp): cond _eval(node.test, env, max_pow) return _eval(node.body if cond else node.orelse, env, max_pow) raise ValueError(f不允许的语法: {type(node).__name__})使用pythonsafe_eval(a 2 * (b - 1), {a: 3, b: 5}) # 11被禁止的语法会直接报错pythonsafe_eval(__import__(os).system(ls)) # ValueError: 不允许的语法: Call4. 如果只处理字面量Python 自带ast.literal_evalpythonimport ast ast.literal_eval({a: [1, 2, 3]})它只允许字面量安全边界较窄但不能计算变量、表达式。5. JS 中的思路不要用jseval(expr) new Function(expr)应使用acorn、espree等解析成 ESTree然后白名单解释允许Literal、Identifier、BinaryExpression、LogicalExpression、UnaryExpression、ConditionalExpression禁止CallExpression、MemberExpression、AssignmentExpression、NewExpression、FunctionExpression、ArrowFunctionExpression、TemplateLiteral、ImportExpression、ThisExpression6. 关键限制与结论AST 安全求值不是“绝对安全”只是大幅缩小攻击面。生产环境还应限制表达式长度、AST 节点数、执行时间、内存禁止Call、Attribute、Subscript、Import、Lambda、推导式、f-string不把模块、函数、对象、类实例传入变量环境必要时放到独立进程、容器、WASM 或 seccomp 沙箱中执行。结论AST 安全求值 解析 白名单遍历 纯解释器 资源限制 默认拒绝。复杂场景建议使用专用表达式引擎如 CEL、JsonLogic、simpleeval、asteval等而不是自己从零实现。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Claude Code示范案例-进阶学习路径 2026/9/30 17:38:48

Claude Code示范案例-进阶学习路径

1. **掌握基础**:熟悉三种工作模式,养成精准描述需求的习惯 2. **深入项目**:学会用 CLAUDE.md 记录项目约定 3. **扩展能力**:探索 MCP、Skills、Hooks 等高级功能 4. **自动化流程**:结合 CI/CD 实现代码审查、自动化…

阅读更多 →
MySQL联合查询详解:UNION与JOIN的核心用法与优化 2026/9/30 17:38:48

MySQL联合查询详解:UNION与JOIN的核心用法与优化

很多人刚接触MySQL的时候,看到“联合查询”这个词,第一反应是“是不是把几张表拼在一起”。这个理解没错,但不够准确。联合查询在MySQL里其实包含了两条技术路线:一条是UNION系列,负责把多个查询结果纵向合并&#xff…

阅读更多 →
SpringBoot 集成 RustFS 2026/9/30 17:38:48

SpringBoot 集成 RustFS

SpringBoot 集成 RustFS1 配置1.1 Docker容器1.2 Spring配置2 依赖3 代码3.1 FileController3.2 RustFsConfig3.3 RustFsProperties3.4 RustFsStorageService1 配置 1.1 Docker容器 services:rustfs:image: rustfs/rustfs:latestcontainer_name: rustfsrestart: unless-stopp…

阅读更多 →
PostgreSQL常用SQL速查:从基础语法到性能调优实战 2026/9/30 17:38:48

PostgreSQL常用SQL速查:从基础语法到性能调优实战

1. 从“PG常用SQL”说起:为什么值得专门整理一套先讲个我自己的经历。很多同学一开始接触的是MySQL,语法熟悉了之后,切到PG(PostgreSQL)数据库,第一反应往往是“不就是SQL嘛,能有多大区别”。结…

阅读更多 →
Deepseek本地知识库实战:Cherry Studio与AnythingLLM部署避坑指南 2026/9/30 17:38:48

Deepseek本地知识库实战:Cherry Studio与AnythingLLM部署避坑指南

简介:本资源是一份面向企业用户与个人开发者的Deepseek大模型本地知识库私有化部署实战指南,聚焦隐私敏感场景下的离线知识管理与智能问答应用。内容系统对比Cherry Studio(非技术人员友好)与AnythingLLM(开发者定制化…

阅读更多 →
Rakazo的7层测试金字塔:如何不烧API额度地验证AI机器人行为 2026/9/30 17:38:36

Rakazo的7层测试金字塔:如何不烧API额度地验证AI机器人行为

Rakazo的7层测试金字塔:如何不烧API额度地验证AI机器人行为 【免费下载链接】rakazo Open-source Grok Bot alternative. Choose your own model and sandbox. 项目地址: https://gitcode.com/gh_mirrors/ra/rakazo Rakazo 是一个开源的 AI 机器人&#xff0…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉