首页 > 其他分享 >SpEL 表达式注入

SpEL 表达式注入

时间:2024-09-12 22:48:57浏览次数:1  
标签:java SpEL org StandardEvaluationContext Expression 表达式 注入

SpEL 表达式注入

spel 是什么

SpEL(Spring Expression Language),即Spring表达式语言,比JSP的EL更强大的一种表达式语言。特别是方法调用和基本的字符串模板功能。Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系,而SpEl可以方便快捷的对ApplicationContext中的Bean进行属性的装配和提取。

什么是EL,OGNL,SpEL?

  • EL:常用于jsp页面,简化jsp页面的操作
  • OGNL:struts中常见
  • SpEL:常用于Spring框架中

spel 依赖

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-expression</artifactId>
      <version>5.0.8.RELEASE</version>
</dependency>

spel 语法

简单 demo

在Java语言中字符串是用""来包裹,但是在SpEL中使用''包裹字符串。尤其注意在parseExpression("'Hello SpEL'")方法中SpEL表达式需要用""来包裹,而不是所谓的#{},只有在注解和XML配置中才这样使用。以下是测试案例:

package org.example.controller;  
  
import org.springframework.expression.Expression;  
import org.springframework.expression.ExpressionParser;  
import org.springframework.expression.spel.standard.SpelExpressionParser;  
  
public class speltest {  
    public static void main(String[] args) {  
        ExpressionParser expressionParser = new SpelExpressionParser();  
        //1.创建expressionParser来解析表达式  
        Expression hello_world = expressionParser.parseExpression("'Hello SpEL'");  
        //2.放置表达式,表达式字符串由单引号''来包裹  
        Object value = hello_world.getValue();  
        System.out.println((String) value);  
        //3.通过Expression对象的getValue()来执行表达式  
    }  
}

在SpEL使用T()运算符会调用类作用域的方法和常量。例如,在SpEL中使用Java的Math类,我们可以像这样使用T()运算符:#{T(java.lang.Math)},该T()运算符的结果会返回一个java.lang.Math类对象。

定义Bean表达式支持

SpEL 表达式可以与基于 XML 或注释的配置元数据一起使用,以定义 BeanDefinitions。在这两种情况下,定义表达式的语法都是 。#{ <expression string> }

SpEL使用 #{...} 作为定界符,所有在大括号中的字符都将被认为是 SpEL表达式,我们可以在其中使用运算符,变量以及引用bean,属性和方法,这样的定界符只是用于xml和注解中,比如可以这样操作:

  • 引用其他对象: #{car}
  • 引用其他对象的属性:#{car.brand}
  • 调用其它方法 , 还可以链式操作:#{car.toString()}

XML中配置

<bean id="numberGuess" class="org.spring.samples.NumberGuess">
    <property name="randomNumber" value="#{ T(java.lang.Math).random() * 100.0 }"/>

    <!-- other properties -->
</bean>

注解中配置

public static class FieldValueTestBean

  @Value("#{ systemProperties['user.region'] }")
  private String defaultLocale;

  public void setDefaultLocale(String defaultLocale)
  {
    this.defaultLocale = defaultLocale;
  }

  public String getDefaultLocale()
  {
    return this.defaultLocale;
  }

}

SpEL 支持有以下功能

Class expressions:类表达式

Method invocation:方法激活

Calling constructors:调用构造方法

Bean references:Bean表达式,如果已使用 Bean 解析程序配置了评估上下文,则可以使用 (@) 符号从表

Variables:变量表达式

User defined functions:定义方法

Templated expressions:模块化表达式

使用SpEL表达式

Class expressions

1.类型表达式

SpEL表达式可以访问(static)静态方法和静态属性,访问它们的时候需要用T()操作符进行声明,括号中需要包含类名的全限定名,也就是包名加上类名。唯一例外的是,SpEL内置了java.lang包下的类声明,也就是说java.lang.String可以通过T(String)访问,而不需要使用全限定名。T()它将返回一个 Class Object,然后可以再调用相应的静态方法或静态属性。这样说可能还不太清楚,横向对比一下

T(java.lang.Runtime)相当于Runtime.class相当于Class.forName("java.lang.Runtime") //显示的类型是一样的

如下面代码即可弹出计算机,

package org.example.controller;  
  
import org.springframework.expression.Expression;  
import org.springframework.expression.ExpressionParser;  
import org.springframework.expression.spel.standard.SpelExpressionParser;  
  
public class speltest {  
    public static void main(String[] args) {  
        ExpressionParser expressionParser = new SpelExpressionParser();  
        Expression hello_world = expressionParser.parseExpression("T(Runtime).getRuntime().exec(\"calc\")");  
        hello_world.getValue();  
  
    }  
}

这里要注意到 Expressionparser 声明了俩个方法,

两种都能进行调用

ExpressionParser expressionParser = new SpelExpressionParser();
//方式1
Expression exp = expressionParser.parseExpression("T(java.lang.Runtime).getRuntime().exec(\"calc\")");

//方式2
Expression exp = expressionParser.parseExpression("#{T(java.lang.Runtime).getRuntime().exec(\"calc\")}",new TemplateParserContext());

2.类实例化

使用new可以直接在SpEL中创建实例,需要创建实例的类要通过全限定名进行访问。如:

ExpressionParser parser = new SpelExpressionParser(); 
Expression exp = parser.parseExpression("new java.util.Date()"); 
Date value = (Date) exp.getValue(); 
System.out.println(value);

SpEL漏洞

EvaluationContext 实现类

实现类区别

EvaluationContext 接口有俩个实现类,分别是 StandardEvaluationContextSimpleEvaluationContext

其中 SimpleEvaluationContext 是一个安全的类,主要的漏洞修复就是靠它来实现的 (但这并不完美,因为我们还需要设置对变量值的过滤)。如果我们不进行设置的话 StandardEvaluationContext 是SpEL默认使用的 EvaluationContext, 我们可以看下SpEL提供的两个 EvaluationContext 的区别。

  • SimpleEvaluationContext - 针对不需要SpEL语言语法的全部范围并且应该受到有意限制的表达式类别,公开SpEL语言特性和配置选项的子集。
  • StandardEvaluationContext - 公开全套SpEL语言功能和配置选项。您可以使用它来指定默认的根对象并配置每个可用的评估相关策略。

总体来说SimpleEvaluationContext旨在仅支持SpEL语言语法的一个子集。它不包括 Java类型引用,构造函数和bean引用。所以说指定正确EvaluationContext,是防止SpEl表达式注入漏洞产生的首选,之前出现过相关的SpEL表达式注入漏洞,其修复方式就是使用SimpleEvaluationContext替代StandardEvaluationContext

demo演示

为了更清楚的展示两种EvaluationContext在处理SpEL功能上的差异,我们举一个例子。这里有一个包含SpEL表达式的恶意字符串:

String inject = "T(java.lang.Runtime).getRuntime().exec('calc.exe')";

StandardEvaluationContext:

StandardEvaluationContext std_c = new StandardEvaluationContext();

SimpleEvaluationContext:

EvaluationContext simple_c = SimpleEvaluationContext.forReadOnlyDataBinding().build();

然后放置表达式:

exp = parser.parseExpression(inject);

然后执行一下试试

java exp.getValue(std_c); //计算器将启动 
java exp.getValue(simple_c); //运行出现错误

看到报错显示

虽然说使用 SimpleEvaluationContext 有助于防止将SpEL注入,但这里还是没有对传入的参数进行安全过滤,因此仍然可以进行拒绝服务攻击(Dos)

SpEL漏洞寻找

为什么会出现SpEL漏洞?问题就在于使用StandardEvaluationContext来处理SpEL表达式,所以我们在勘察这类漏洞的时候就需要寻找在什么位置使用StandardEvaluationContext来处理表达式。

CVE-2018-1273 Spring Data Commons RCE

  • 手动发现
  • findsecbugs-cil插件
  • LGTM QL

手动发现

手动发现思路:ExpressionParser类----getValue()方法----EvaluationContext

看到这里的 context 为传入的 StandardEvaluationContext,然后获得 ExpressionState 后执命令

参考:https://www.cnblogs.com/BUTLER/articles/16453114.html

标签:java,SpEL,org,StandardEvaluationContext,Expression,表达式,注入
From: https://www.cnblogs.com/gaorenyusi/p/18411264

相关文章

  • 【C语言基础】数据类型、运算符和表达式
    1数据类型基本类型整型:短整型,基本整型,长整型字符型实型(浮点型):单精度型,双精度型枚举类型构造类型:是使用基本类型的数据或者使用已经构造好的数据类型,进行添加、设计构造出新的数据类型,使其设计的新构造类型满足待解决问题所需要的数据类型。数组类型结构体类型共用体类......
  • Springboot项目部署时使用Mail注入Bean时的Constructor threw exception
    缘起:今天打算把写了好一段时间的项目提溜到服务器上转转,然后在启动的时候就发现了个问题,在日志跑到【JobFactorysetto:org.springframework.scheduling.quartz.SpringBeanJobFactory@31e7afde】的时候他就不动了,然后等了好一会他才抛出了个异常【org.springframework.beans.f......
  • vue优点/插值表达式/强制绑定
    1.Vue.js的优点体积小:压缩后只有33k;更高的运行效率:基于虚拟DOM,一种可以预先通过JavaScript进行各种计算,把最终的DOM操作计算出来并优化的技术,由于这种DOM操作属于预处理操作,并没有真实的操作DOM,所以叫做虚拟DOM;双向数据绑定:让开发者不用再去操作DOM对象,把更多的精力投入到业务......
  • c++primer第五章循环和关系表达式学习笔记
    for循环简单for循环#include<iostream>usingnamespacestd;intmain(){//5.1inti;for(i=0;i<5;i++)cout<<"C++knowsloops.\n";cout<<"C++knowswhentostop.\n";return0;}for循环组成部分#......
  • 通过 Dll 注入实现应用层跨进程 inline 挂钩
    一、导入Detours库Detours是微软提供的一个开发库,可以简单、高效且稳定的实现APIhook。Detours是一个可以在x86、x64和IA64平台上挂钩任意win32函数的程序开发库,它通过在需要进行挂钩的目标函数头部重写内存代码而达到接管函数控制权,进而实现自己功能的目的。除此之......
  • 基于sqli-labs Less-1的sql注入原理详细讲解
    SQLiLabs是一个专为学习和测试SQL注入漏洞而设计的实验室平台。它旨在帮助安全研究人员、开发者以及网络安全爱好者深入理解和实践各种SQL注入攻击。SQLiLabs提供了一系列精心设计的实验室环境和挑战,模拟真实的SQL注入漏洞,并提供相应的解决方案。关于sqli-labs靶场的本......
  • 带你了解Android Jetpack库中的依赖注入框架:Hilt
    本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点Hilt概述Hilt是Google推出的一种用于Android的依赖注入(DependencyInjection,DI)框架,构建于Dagger之上,旨在简化Android应用中的依赖注入过程。通过Hilt,你可以更轻松......
  • 使用Java实现字符串中的表达式计算
    /***计算字符串表达式的值,不支持小数*<ul>*<li>加法('+')</li>*<li>减法('-')</li>*<li>乘法('*')</li>*<li>除法,保留两位小数('/')</li>*<li>取余,获取商('......
  • sql-server公用表表达式
    视图是作为数据库对象存储在数据库中的,如果这个结果集仅仅要使用一次,那么建立视图就太奢侈了。在SQLServer中,公共表表达式(CommonTableExpression,简称CTE)是一种临时的结果集,可以在一个查询块中多次引用。CTE可以用来简化复杂的查询,特别是那些需要多步操作或者递归查询的情况......
  • Java中的安全编码实践:如何防止SQL注入与XSS攻击
    Java中的安全编码实践:如何防止SQL注入与XSS攻击大家好,我是微赚淘客返利系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!在Java开发中,安全编码是确保应用程序免受攻击的关键因素。SQL注入和跨站脚本攻击(XSS)是最常见的安全漏洞之一。本文将介绍如何在Java中防止这两种攻击,并提......