Java代码审计之SpEL注入
一. SpEL 简介
SpEL,全称为 Spring 表达式语言(Spring Expression Language),是一个由 Spring 框架提供的表达式语言。它是一种基于字符串的表达式语言,可以在运行时对对象进行查询和操作。
SpEL 支持在XML和注解配置中使用,它可以在Spring框架的各种组件中使用,如Spring MVC 控制器、Spring Security 安全框架、Spring Data 数据访问框架等。它可以方便地访问对象的属性、调用对象的方法、进行数学运算、逻辑运算、正则表达式匹配等操作。
使用 SpEL 可以大大简化编程工作,使得配置和编写代码更加灵活和易于维护。例如,可以使用 SpEL 在XML 或注解中配置 Spring bean 的属性,或在 Spring MVC 控制器中动态地计算请求参数。
总而言之,SpEL 是 Spring 框架中一个非常有用的特性,它提供了一种灵活、简洁的方式来操作和查询对象。
http://itmyhome.com/spring/expressions.html 基础知识
SpEL 表达式语言支持以下功能:
1 | |
1.2 表达式符号
在 SpEL 中,使用 #{<表达式>} 界定符被认为是 SpEL 表达式,可以使用相关变量、属性和方法等操作。
1.3 类型表达式 T(package.ClassName)
T(type) 用于获取一个类型的 Class 对象。它的作用是让 SpEL 表达式在运行时获取指定的类型的 Class 对象,以便在表达式中可以使用该类的方法和属性。
使用 T(type) 的语法格式为:T(package.ClassName),其中 package 是指类所在的包名,ClassName是指类名。例如,要获取java.lang.String 类的 Class 对象,可以使用表达式 T(java.lang.String)。
在 SpEL 中,同样可以使用 T(type) 来调用静态方法和属性,例如:T(java.lang.Math).PI 表示获取 Math 类中的 PI 静态属性,T(java.lang.Math).random() 表示调用 Math 类中的 random() 静态方法。
需要注意的是,在使用 T(type) 操作符时,要确保指定的类型已经被加载,否则会抛出ClassNotFoundException 异常。
1.4 SpEL 用法
SpEL 的用法有三种形式:一是在注解中,二是在 XML 配置中,三是在代码中使用 Expression。
在注解中:
在 Spring 中,可以使用 @Value 注解将 SpEL 表达式应用于 Bean 属性、构造函数参数和集合元素等场景。@Value 注解可以将 SpEL 表达式注入到 Bean 的属性中,支持在表达式中引用其他 Bean、属性和环境变量等。
1 | |
在 XML 配置中:
在 Spring 中,可以在 XML 配置中使用 SpEL 表达式来配置 Bean。SpEL 表达式可以在 XML 配置中用 #{expression} 的形式引用。
1 | |
在代码块中使用 Expression:
在 Spring 中,可以使用 SpEL 的 Expression 接口在代码块中使用 SpEL 表达式。使用 Expression 接口可以在运行时编译和评估表达式,也可以设置变量和函数等。
1 | |
1.5 SpEL 的 EvaluationContext 接口
在使用 SpEL 时,我们需要将表达式与 EvaluationContext 进行绑定,然后将表达式交给 SpEL 引擎执行。EvaluationContext 为 SpEL 引擎提供了上下文信息,使得 SpEL 引擎能够正确地解析表达式中的变量、函数等信息,从而求出表达式的结果。
SimpleEvaluationContext 和 StandardEvaluationContext 都是 SpEL 提供的 EvaluationContext 的实现类。
它们都提供了表达式求值所需的上下文信息,但是在具体实现方面略有不同。
SimpleEvaluationContext 相对来说比较简单,它仅仅包含了变量解析器和类型转换器,不支持函数表达式。
而 StandardEvaluationContext 提供了更丰富的上下文信息,包括变量解析器、类型转换器和函数表达式等。同时, StandardEvaluationContext 还支持自定义函数和类加载器等高级功能。
通常情况下,如果只是简单的表达式求值,可以使用 SimpleEvaluationContext;如果需要使用函数表达式或自定义函数等高级功能,可以使用 StandardEvaluationContext。
二. SpEL 注入漏洞
简单来说,当应用程序使用 SpEL 时,如果未正确处理用户输入数据,攻击者可以在表达式中注入任意的代码,并在应用程序的上下文中执行它,进而造成命令执行等漏洞。在上面提到了 SpEL 的 EvaluationContext,其中 StandardEvaluationContext 使用方法更加完整。因此,触发 SpEL 的漏洞的流程大致为:
- 接收了用户的输入且未过滤等操作,将接收的参数使StandardEvaluationContext 去处理
- 并对表达式调用了 getValue() 或 setValue() 方法。如上流程,后端接收了用户输入且未过滤,而攻击者精心构造攻击 payload 即可实现命令执行等危险操作。
1 | |