Ognl小trick
字数 1285 2025-08-19 12:42:22
OGNL表达式深入解析与实战技巧
1. OGNL概述
1.1 什么是OGNL表达式
OGNL(Object-Graph Navigation Language,对象图导航语言)最初作为WebWork框架的一部分开发,现已成为Apache Struts2的关键组件,并被广泛应用于各种Java框架中。
1.2 对象图导航概念
OGNL的核心在于对象图导航,类似于数据结构中的图:
- 节点:表示对象
- 边:表示对象间的引用关系
示例代码说明:
public class ObjectGraphDemo {
class People {
Car car;
}
class Car {
String carName = "BMW";
House house;
}
class House {
String houseName = "MyHouse";
}
public void printPeopleInfo() {
People people = new People();
System.out.println(people.car.carName); // 导航到carName
System.out.println(people.car.house.houseName); // 导航到houseName
}
}
2. OGNL核心三要素
OGNL操作必不可少的三个组成部分:
2.1 expression(表达式)
- OGNL的核心部分
- 规定解析后需要执行的操作
2.2 root(根对象)
- 表达式解析后操作的目标对象
- 可以看作图中的一个节点
2.3 context(上下文)
- Map类型的数据结构
- 包含OGNL表达式执行的上下文信息(root也在其中)
3. OGNL基本使用
3.1 基本语法
OGNL语法与Java类似,支持以下操作符:
- 算术运算符:
+, -, *, /, ++, -- - 比较运算符:
==, !=, = - 其他运算符:
mod, in, not in
3.2 对象访问
- 非root对象:使用
#前缀,如#people1.car.carName - root对象:直接访问,如
stratt[1]
3.3 静态资源引用
引用类的静态方法和字段:
@class@member 或 @class@method(args)
示例(执行系统命令):
@java.lang.Runtime@getRuntime().exec("calc")
3.4 集合操作
数组操作
public class People {
public Car car = new Car();
public String[] stratt = new String[]{"1", "2", "3"};
}
访问方式:
- root:
stratt[1] - 非root:
#people1.stratt[2] - 新建数组:
new java.lang.String[]{"a","b","c"}[1]
Map操作
#{"A":"a","B":"b","C":"c"}["B"]
3.5 选择和投影
投影(Projection)
从集合中提取相同属性组成新集合:
group.userList.{username} // 获取所有user的name列表
选择(Selection)
过滤集合元素:
?:选择满足条件的所有元素^:选择满足条件的第一个元素$:选择满足条件的最后一个元素
示例:
group.userList.{? #txxx.xxx != null} // 获取name不为空的user列表
4. 高级技巧:Invocation.class结合OGNL
4.1 技术背景
在MyBatis等框架中频繁使用setAccessible()方法,可以通过Invocation.class绕过反射限制。
4.2 实战应用
- 检测类是否存在:
forName() - 构造表达式获取Runtime实例,绕过防护
4.3 测试用例
具体测试用例可参考:OGNL-Test GitHub仓库
5. 安全注意事项
OGNL表达式在Struts2等框架中频繁出现安全漏洞,主要原因包括:
- 表达式直接执行系统命令的能力
- 反射机制的滥用
- 上下文环境的不当配置
开发人员应特别注意对用户输入的OGNL表达式进行严格过滤和验证。
6. 总结
OGNL作为强大的对象图导航语言,提供了:
- 灵活的对象访问和操作能力
- 丰富的集合处理功能
- 静态方法和字段的直接调用
- 高级选择和投影特性
同时,其强大的功能也带来了安全风险,需要谨慎使用。理解OGNL的核心三要素(expression、root、context)是掌握其用法的关键。