Java OgnlMVEL and JEXL表达式注入漏洞成因及细节
字数 1457 2025-08-10 09:16:21
Java表达式注入漏洞详解:OGNL、MVEL与JEXL
前言
本文全面分析Java中常见的表达式注入漏洞类型及其原理,重点介绍OGNL(Object-Graph Navigation Language)、MVEL和JEXL三种表达式语言的特性、使用方式及安全风险。
OGNL表达式语言
背景与特点
OGNL是一种功能强大的表达式语言,具有以下特点:
- 通过简单一致的表达式语法存取对象任意属性
- 可调用对象方法
- 能遍历整个对象结构图
- 实现字段类型转化等功能
- 使用Java反射和内省机制在运行时解析对象图
基本语法
-
类静态方法调用和值访问:
@[类全名(包括包路径)]@[方法名|值名] -
访问OGNL上下文(OGNL context)和ActionContext
-
对象创建:
new 对象 -
容器变量访问:
使用#符号 -
投影和选择:
- 选择:
collection.{X YYY},其中X是选择操作符(?、^、$),YYY是选择用的逻辑表达式 - 投影:
collection.{XXX},XXX是集合中每个元素的公共属性
- 选择:
-
语法树形式:
(expression)(constant) = value(constant)((expression1)(expression2))
-
符号区别:
@:获取静态函数和变量.:获取非静态函数#:获取非静态变量
ActionContext对象
ActionContext是一个基于MAP结构的上下文对象,使用键值对描述对象属性及值。包含以下作用域:
request:请求作用域session:会话作用域application:应用作用域attr:保存上述三个作用域的所有属性(重复时以request域为准)paramters:保存表单提交参数VALUE_STACK:值栈,保存valueStack对象
表达式解析示例
@RequestMapping("/ognl")
@ResponseBody
public String OgnlTest(@RequestParam(required = false) String expression) {
if (expression == null) {
return "Send request with \"expression\" parameter!";
}
try {
OgnlContext ognlContext = new OgnlContext();
Ognl.getValue(expression, ognlContext, ognlContext.getRoot());
} catch (Exception e) {
return Util.printStack(e);
}
return "OK!";
}
解析过程分析
-
表达式解析:
- 调用
Ognl.getValue()方法 - 内部调用
parseExpression方法构建AST(抽象语法树)结构 - 在OGNL中表现为
ASTChain类数据结构 - 不同语句被抽象为
SimpleNode抽象类的各种实现类:- 方法调用:
ASTMethod - 构造方法:
ASTCtor
- 方法调用:
- 调用
-
表达式求值:
- 循环调用每个节点的
getValue方法 - 核心逻辑在各节点实现的
getValueBody方法中ASTCtor#getValueBody:通过Class.forName获取目标类ASTMethod:封装方法调用并执行
- 循环调用每个节点的
表达式注入漏洞成因
表达式注入漏洞通常发生在以下场景:
- 应用程序接受用户输入作为表达式直接解析
- 解析器未对表达式内容进行安全过滤
- 表达式语言功能过于强大,允许执行任意代码
攻击向量示例
攻击者可以构造恶意表达式实现:
- 任意Java代码执行
- 系统命令执行
- 敏感信息泄露
- 服务器文件系统访问
防御措施
-
输入验证:
- 严格限制用户输入的表达式内容
- 使用白名单机制允许特定语法
-
沙箱环境:
- 在受限环境中执行表达式
- 限制可访问的类和方法
-
安全配置:
- 禁用危险的功能和操作符
- 设置适当的安全管理器
-
替代方案:
- 使用功能受限的表达式语言
- 考虑使用模板引擎替代
总结
OGNL、MVEL和JEXL等表达式语言虽然提供了强大的功能,但也带来了严重的安全风险。开发人员必须充分了解这些技术的内部工作原理,在享受便利性的同时确保应用程序的安全性。通过合理的输入验证、安全配置和沙箱环境,可以有效降低表达式注入漏洞的风险。