使用CodeQL挖掘Spring中的大量赋值漏洞
字数 2025 2025-09-01 11:26:17

Spring框架中的大量赋值漏洞分析与CodeQL挖掘技术

1. 大量赋值漏洞概述

1.1 基本概念

大量赋值(Mass Assignment)漏洞是指后端为了简化开发流程,自动将请求参数绑定到后端对象的属性上,但开发者没有限制哪些字段可以被赋值,导致攻击者可能注入原本不应由用户控制的敏感字段。

1.2 常见表现形式

  1. 在获取用户列表请求中FUZZ SQL关键字

    • 示例:/api/user?name=ad&orderby=id&sort=desc,1/0&limit=0,1 PROCEDURE ANALYSE(..)
  2. 在注册账号场景中FUZZ内部字段

    • 示例:尝试设置role=adminisAdmin=true

1.3 漏洞本质

后端接收了本不应暴露给用户的字段并进行处理,特别是当框架自动将请求参数绑定到对象属性时,如果没有适当的限制机制。

2. Spring框架中的大量赋值漏洞

2.1 Spring框架简介

Spring Framework是一个开源的Java应用程序开发框架,以其轻量级、模块化和强大的依赖注入(DI)与面向切面编程(AOP)特性而广受欢迎。

2.2 @RequestBody注解的风险

在Spring Web开发中,@RequestBody注解能够将HTTP请求体中的JSON、XML等结构化数据反序列化为Java对象。这种自动映射机制可能引入安全隐患:

  • 自动绑定请求体数据到对象属性
  • 如果没有字段限制,攻击者可注入敏感字段
  • 可能导致权限提升等安全问题

2.3 漏洞示例分析

2.3.1 用户注册功能示例

User类定义

public class User {
    private String username;
    private String password;
    private String role;  // 默认为"user"
    // getters and setters
}

Controller代码

@PostMapping("/register")
public String register(@RequestBody User user) {
    userService.save(user);  // 直接保存用户对象
    return "注册成功";
}

数据库表结构

CREATE TABLE User (
    username VARCHAR(255),
    password VARCHAR(255),
    role VARCHAR(255) DEFAULT 'user'
);

前端请求

{
    "username": "attacker",
    "password": "123456"
}

攻击者请求

{
    "username": "attacker",
    "password": "123456",
    "role": "admin"  // 注入管理员权限
}

2.3.2 修复方案

在保存前显式设置role字段:

@PostMapping("/register")
public String register(@RequestBody User user) {
    user.setRole("user");  // 显式设置角色
    userService.save(user);
    return "注册成功";
}

3. 使用CodeQL挖掘大量赋值漏洞

3.1 CodeQL分析目标

通过CodeQL查找:

  1. 使用@RequestBody注解的参数
  2. 参数类型为指定的数据结构
  3. 未使用显式调用setter方法进行字段赋值

3.2 分析步骤详解

3.2.1 查找使用@RequestBody注解的参数

参考官方annotations-in-java案例:

from Parameter p
where p.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestBody")
select p

3.2.2 筛选特定类型的参数

定义绑定参数类型(示例中为org.linlinjava.litemall.db.domain包下,符合LitemallXXX命名格式):

predicate isTargetType(RefType r) {
    r.getPackage().getName() = "org.linlinjava.litemall.db.domain" and
    r.getName().matches("Litemall%")
}

整合为BodyParameter类:

class BodyParameter extends Parameter {
    BodyParameter() {
        this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestBody") and
        isTargetType(this.getType())
    }
}

3.2.3 查找未显式调用的setter方法

定义SetterMethod类:

class SetterMethod extends Method {
    SetterMethod() {
        this.isPublic() and
        this.getName().matches("set%") and
        this.getNumberOfParameters() = 1
    }
}

查询未显式调用的setter:

from BodyParameter bp, SetterMethod sm
where not exists(MethodAccess ma | 
    ma.getMethod() = sm and 
    ma.getEnclosingCallable() = bp.getCallable()
)
select bp, sm

3.2.4 优化查询:限制用户可访问API

添加可访问性限制:

// 添加可访问性条件
where ...
and bp.getCallable().getDeclaringType().getASupertype*().hasQualifiedName("org.springframework.web.bind.annotation", "RestController")

3.2.5 变量传递优化

确保参数传递到service层处理:

class ServiceClass extends RefType {
    ServiceClass() {
        this.getName().matches("%Service") and
        this.getPackage().getName() = "org.linlinjava.litemall.db.service"
    }
}

// 添加数据流分析
where ...
and exists(DataFlow::Node source, DataFlow::Node sink |
    DataFlow::localFlow(source, sink) and
    source.asExpr() = bp.getAnAccess() and
    sink.asExpr().(MethodAccess).getMethod().getDeclaringType() instanceof ServiceClass
)

3.2.6 处理getter方法调用

过滤掉使用getter方法对应的setter方法:

class GetterMethod extends Method {
    GetterMethod() {
        this.isPublic() and
        this.getName().matches("get%") and
        this.getNumberOfParameters() = 0
    }
}

// 在where条件中添加
where ...
and not exists(MethodAccess ma |
    ma.getMethod().getName() = sm.getName().replaceAll("set", "get") and
    ma.getEnclosingCallable() = bp.getCallable()
)

3.3 完整CodeQL查询示例

import java
import semmle.code.java.dataflow.DataFlow

predicate isTargetType(RefType r) {
    r.getPackage().getName() = "org.linlinjava.litemall.db.domain" and
    r.getName().matches("Litemall%")
}

class BodyParameter extends Parameter {
    BodyParameter() {
        this.getAnAnnotation().getType().hasQualifiedName("org.springframework.web.bind.annotation", "RequestBody") and
        isTargetType(this.getType())
    }
}

class SetterMethod extends Method {
    SetterMethod() {
        this.isPublic() and
        this.getName().matches("set%") and
        this.getNumberOfParameters() = 1
    }
}

class GetterMethod extends Method {
    GetterMethod() {
        this.isPublic() and
        this.getName().matches("get%") and
        this.getNumberOfParameters() = 0
    }
}

class ServiceClass extends RefType {
    ServiceClass() {
        this.getName().matches("%Service") and
        this.getPackage().getName() = "org.linlinjava.litemall.db.service"
    }
}

from BodyParameter bp, SetterMethod sm
where 
    not exists(MethodAccess ma | 
        ma.getMethod() = sm and 
        ma.getEnclosingCallable() = bp.getCallable()
    ) and
    bp.getCallable().getDeclaringType().getASupertype*().hasQualifiedName("org.springframework.web.bind.annotation", "RestController") and
    exists(DataFlow::Node source, DataFlow::Node sink |
        DataFlow::localFlow(source, sink) and
        source.asExpr() = bp.getAnAccess() and
        sink.asExpr().(MethodAccess).getMethod().getDeclaringType() instanceof ServiceClass
    ) and
    not exists(MethodAccess ma |
        ma.getMethod().getName() = sm.getName().replaceAll("set", "get") and
        ma.getEnclosingCallable() = bp.getCallable()
    )
select bp, sm, "Potential mass assignment vulnerability: " + sm.getName()

4. 实际漏洞案例:CVE-2025-6702

4.1 漏洞发现过程

通过上述CodeQL查询,发现以下关键点:

  1. setAdminContent方法未被显式调用

    • 该字段为"管理员回复内容"
    • 攻击者可自行设置管理员回复
  2. setDeleted方法未被显式调用

    • 允许用户自删除自己的评论/数据

4.2 漏洞利用细节

攻击者可构造如下请求:

POST /wx/comment/post
{
    "content": "正常评论",
    "adminContent": "伪造的管理员回复",
    "deleted": false
}

通过修改adminContentdeleted字段,实现非预期的功能操作。

5. 防御措施

5.1 最佳实践

  1. 显式设置敏感字段:在保存前显式设置不应由用户控制的字段
  2. 使用DTO模式:创建专用的数据传输对象,仅包含允许用户设置的字段
  3. 字段白名单:使用@JsonIgnoreProperties(ignoreUnknown = true)或类似注解
  4. 输入验证:对所有用户输入进行严格验证

5.2 Spring特定防御

  1. 使用@JsonView控制序列化/反序列化的字段
  2. 实现WebDataBinder自定义数据绑定规则
  3. 使用@InitBinder限制可绑定的字段

6. 总结

大量赋值漏洞是现代Web框架中常见的安全问题,特别是在使用自动绑定功能的框架如Spring中。通过CodeQL等静态分析工具,可以有效地发现这类漏洞。开发者应当始终遵循最小权限原则,显式控制哪些字段可以由用户设置,从而避免此类安全问题。

7. 参考资源

  1. OWASP API Security: Broken Object Property Level Authorization
  2. PortSwigger Web Security: Mass Assignment Vulnerabilities
  3. CodeQL for Java documentation
  4. OWASP Web Security Testing Guide: Testing for Mass Assignment
Spring框架中的大量赋值漏洞分析与CodeQL挖掘技术 1. 大量赋值漏洞概述 1.1 基本概念 大量赋值(Mass Assignment)漏洞是指后端为了简化开发流程,自动将请求参数绑定到后端对象的属性上,但开发者没有限制哪些字段可以被赋值,导致攻击者可能注入原本不应由用户控制的敏感字段。 1.2 常见表现形式 在获取用户列表请求中FUZZ SQL关键字 示例: /api/user?name=ad&orderby=id&sort=desc,1/0&limit=0,1 PROCEDURE ANALYSE(..) 在注册账号场景中FUZZ内部字段 示例:尝试设置 role=admin 或 isAdmin=true 1.3 漏洞本质 后端接收了本不应暴露给用户的字段并进行处理,特别是当框架自动将请求参数绑定到对象属性时,如果没有适当的限制机制。 2. Spring框架中的大量赋值漏洞 2.1 Spring框架简介 Spring Framework是一个开源的Java应用程序开发框架,以其轻量级、模块化和强大的依赖注入(DI)与面向切面编程(AOP)特性而广受欢迎。 2.2 @RequestBody注解的风险 在Spring Web开发中, @RequestBody 注解能够将HTTP请求体中的JSON、XML等结构化数据反序列化为Java对象。这种自动映射机制可能引入安全隐患: 自动绑定请求体数据到对象属性 如果没有字段限制,攻击者可注入敏感字段 可能导致权限提升等安全问题 2.3 漏洞示例分析 2.3.1 用户注册功能示例 User类定义 : Controller代码 : 数据库表结构 : 前端请求 : 攻击者请求 : 2.3.2 修复方案 在保存前显式设置role字段: 3. 使用CodeQL挖掘大量赋值漏洞 3.1 CodeQL分析目标 通过CodeQL查找: 使用 @RequestBody 注解的参数 参数类型为指定的数据结构 未使用显式调用setter方法进行字段赋值 3.2 分析步骤详解 3.2.1 查找使用@RequestBody注解的参数 参考官方annotations-in-java案例: 3.2.2 筛选特定类型的参数 定义绑定参数类型(示例中为 org.linlinjava.litemall.db.domain 包下,符合 LitemallXXX 命名格式): 整合为 BodyParameter 类: 3.2.3 查找未显式调用的setter方法 定义 SetterMethod 类: 查询未显式调用的setter: 3.2.4 优化查询:限制用户可访问API 添加可访问性限制: 3.2.5 变量传递优化 确保参数传递到service层处理: 3.2.6 处理getter方法调用 过滤掉使用getter方法对应的setter方法: 3.3 完整CodeQL查询示例 4. 实际漏洞案例:CVE-2025-6702 4.1 漏洞发现过程 通过上述CodeQL查询,发现以下关键点: setAdminContent 方法未被显式调用 该字段为"管理员回复内容" 攻击者可自行设置管理员回复 setDeleted 方法未被显式调用 允许用户自删除自己的评论/数据 4.2 漏洞利用细节 攻击者可构造如下请求: 通过修改 adminContent 和 deleted 字段,实现非预期的功能操作。 5. 防御措施 5.1 最佳实践 显式设置敏感字段 :在保存前显式设置不应由用户控制的字段 使用DTO模式 :创建专用的数据传输对象,仅包含允许用户设置的字段 字段白名单 :使用 @JsonIgnoreProperties(ignoreUnknown = true) 或类似注解 输入验证 :对所有用户输入进行严格验证 5.2 Spring特定防御 使用 @JsonView 控制序列化/反序列化的字段 实现 WebDataBinder 自定义数据绑定规则 使用 @InitBinder 限制可绑定的字段 6. 总结 大量赋值漏洞是现代Web框架中常见的安全问题,特别是在使用自动绑定功能的框架如Spring中。通过CodeQL等静态分析工具,可以有效地发现这类漏洞。开发者应当始终遵循最小权限原则,显式控制哪些字段可以由用户设置,从而避免此类安全问题。 7. 参考资源 OWASP API Security: Broken Object Property Level Authorization PortSwigger Web Security: Mass Assignment Vulnerabilities CodeQL for Java documentation OWASP Web Security Testing Guide: Testing for Mass Assignment