记一次审计的奇思妙想
字数 1319 2025-08-09 17:09:35

奇安信攻防社区漏洞审计实战教学文档

一、目标系统分析

1.1 系统架构识别

  • 目标系统采用Java语言开发
  • 使用Spring框架(Spring MVC)
  • 数据库交互使用MyBatis
  • 前端使用Thymeleaf模板引擎

1.2 关键组件分析

  • Spring Security:负责身份认证和授权
  • Apache Commons FileUpload:文件上传组件
  • Jackson:JSON处理库
  • Hibernate Validator:数据验证框架

二、审计前准备

2.1 环境搭建

  1. 使用IDEA导入项目
  2. 配置Maven依赖
  3. 设置调试环境
  4. 准备测试数据库

2.2 代码审计工具

  • 静态分析工具:Fortify、Checkmarx
  • 动态分析工具:Burp Suite、Postman
  • 辅助工具:JD-GUI、JADX(用于反编译)

三、漏洞挖掘过程

3.1 SQL注入漏洞

发现点

@GetMapping("/user/info")
public String getUserInfo(@RequestParam String userId) {
    String sql = "SELECT * FROM users WHERE id = " + userId;
    // 直接拼接SQL查询
    return jdbcTemplate.queryForObject(sql, String.class);
}

漏洞原理

  • 直接拼接用户输入的userId到SQL语句
  • 未使用预编译语句或参数化查询
  • 未进行任何输入过滤

修复建议

@GetMapping("/user/info")
public String getUserInfo(@RequestParam String userId) {
    String sql = "SELECT * FROM users WHERE id = ?";
    return jdbcTemplate.queryForObject(sql, new Object[]{userId}, String.class);
}

3.2 XSS漏洞

发现点

@PostMapping("/comment/add")
public String addComment(@RequestParam String content, Model model) {
    model.addAttribute("comment", content);
    return "comment/show";
}

Thymeleaf模板

<div th:utext="${comment}"></div>

漏洞原理

  • 使用th:utext而非th:text渲染用户输入
  • 未对用户输入的content进行任何过滤或转义

修复建议

  1. 使用th:text替代th:utext
  2. 添加XSS过滤器:
public class XssFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
        throws IOException, ServletException {
        chain.doFilter(new XssRequestWrapper((HttpServletRequest) request), response);
    }
}

3.3 文件上传漏洞

发现点

@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
    String fileName = file.getOriginalFilename();
    File dest = new File("/uploads/" + fileName);
    file.transferTo(dest);
    return "upload success";
}

漏洞原理

  1. 未验证文件类型
  2. 未重命名上传文件
  3. 直接使用原始文件名可能导致目录穿越

修复建议

@PostMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile file) {
    // 验证文件类型
    String contentType = file.getContentType();
    if (!Arrays.asList("image/jpeg", "image/png").contains(contentType)) {
        throw new RuntimeException("Invalid file type");
    }
    
    // 生成随机文件名
    String fileName = UUID.randomUUID().toString() + 
                     FilenameUtils.getExtension(file.getOriginalFilename());
    
    // 防止目录穿越
    fileName = fileName.replace("../", "");
    
    File dest = new File("/uploads/" + fileName);
    file.transferTo(dest);
    return "upload success";
}

3.4 权限绕过漏洞

发现点

@GetMapping("/admin/deleteUser")
public String deleteUser(@RequestParam String userId) {
    // 直接执行删除操作,未检查权限
    userService.deleteUser(userId);
    return "success";
}

漏洞原理

  • 缺少权限验证注解(如@PreAuthorize)
  • 仅依赖前端隐藏管理接口

修复建议

@GetMapping("/admin/deleteUser")
@PreAuthorize("hasRole('ADMIN')")
public String deleteUser(@RequestParam String userId) {
    userService.deleteUser(userId);
    return "success";
}

四、高级审计技巧

4.1 反序列化漏洞检测

检测点

  1. 查找接收JSON/XML输入的接口
  2. 检查是否使用不安全的ObjectMapper配置:
ObjectMapper mapper = new ObjectMapper();
mapper.enableDefaultTyping(); // 危险配置

修复建议

ObjectMapper mapper = new ObjectMapper();
// 禁用默认类型
mapper.deactivateDefaultTyping();
// 使用安全的@JsonTypeInfo注解替代

4.2 表达式注入检测

检测点

  1. 查找使用SpEL表达式的代码
@PreAuthorize("#userId == authentication.principal.userId")
public String getUserInfo(String userId) {
    // ...
}
  1. 检查Thymeleaf表达式中是否包含用户输入

修复建议

  • 避免在安全表达式中直接使用用户输入
  • 对表达式中的变量进行严格校验

4.3 不安全的加密实现

常见问题

  1. 使用弱哈希算法(MD5、SHA1)
  2. 硬编码加密密钥
  3. 使用ECB模式加密

修复建议

// 使用PBKDF2或bcrypt进行密码哈希
String hashedPassword = BCrypt.hashpw(password, BCrypt.gensalt());

// 使用AES-GCM模式加密
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

五、自动化审计辅助

5.1 自定义规则编写

Fortify自定义规则示例

<Rule formatVersion="3.4" language="java">
    <Pattern>jdbcTemplate.queryForObject($sql, $...)</Pattern>
    <Description>Potential SQL injection</Description>
    <Category>SQL Injection</Category>
    <Severity>High</Severity>
</Rule>

5.2 代码审计检查清单

  1. 输入验证

    • 所有用户输入是否经过验证
    • 是否使用白名单验证
  2. 输出编码

    • 动态内容是否正确编码
    • 是否区分HTML、JS、CSS等上下文
  3. 身份认证

    • 密码存储是否使用强哈希
    • 会话管理是否安全
  4. 访问控制

    • 是否实施最小权限原则
    • 是否进行服务端权限检查
  5. 错误处理

    • 是否泄露敏感信息
    • 是否使用自定义错误页面

六、总结与最佳实践

6.1 审计经验总结

  1. 不要过度依赖工具,人工分析必不可少
  2. 关注框架的错误配置和安全特性禁用
  3. 特别注意业务逻辑中的安全缺陷
  4. 跟踪数据从入口到最终使用的完整流程

6.2 安全开发建议

  1. 采用安全编码规范
  2. 实施SDL流程
  3. 定期进行安全培训
  4. 建立代码审查制度

6.3 持续学习资源

  1. OWASP Top 10
  2. CWE/SANS Top 25
  3. 框架官方安全文档
  4. 安全社区漏洞分享
奇安信攻防社区漏洞审计实战教学文档 一、目标系统分析 1.1 系统架构识别 目标系统采用Java语言开发 使用Spring框架(Spring MVC) 数据库交互使用MyBatis 前端使用Thymeleaf模板引擎 1.2 关键组件分析 Spring Security :负责身份认证和授权 Apache Commons FileUpload :文件上传组件 Jackson :JSON处理库 Hibernate Validator :数据验证框架 二、审计前准备 2.1 环境搭建 使用IDEA导入项目 配置Maven依赖 设置调试环境 准备测试数据库 2.2 代码审计工具 静态分析工具 :Fortify、Checkmarx 动态分析工具 :Burp Suite、Postman 辅助工具 :JD-GUI、JADX(用于反编译) 三、漏洞挖掘过程 3.1 SQL注入漏洞 发现点 漏洞原理 直接拼接用户输入的userId到SQL语句 未使用预编译语句或参数化查询 未进行任何输入过滤 修复建议 3.2 XSS漏洞 发现点 Thymeleaf模板 漏洞原理 使用 th:utext 而非 th:text 渲染用户输入 未对用户输入的content进行任何过滤或转义 修复建议 使用 th:text 替代 th:utext 添加XSS过滤器: 3.3 文件上传漏洞 发现点 漏洞原理 未验证文件类型 未重命名上传文件 直接使用原始文件名可能导致目录穿越 修复建议 3.4 权限绕过漏洞 发现点 漏洞原理 缺少权限验证注解(如@PreAuthorize) 仅依赖前端隐藏管理接口 修复建议 四、高级审计技巧 4.1 反序列化漏洞检测 检测点 查找接收JSON/XML输入的接口 检查是否使用不安全的ObjectMapper配置: 修复建议 4.2 表达式注入检测 检测点 查找使用SpEL表达式的代码 检查Thymeleaf表达式中是否包含用户输入 修复建议 避免在安全表达式中直接使用用户输入 对表达式中的变量进行严格校验 4.3 不安全的加密实现 常见问题 使用弱哈希算法(MD5、SHA1) 硬编码加密密钥 使用ECB模式加密 修复建议 五、自动化审计辅助 5.1 自定义规则编写 Fortify自定义规则示例 5.2 代码审计检查清单 输入验证 : 所有用户输入是否经过验证 是否使用白名单验证 输出编码 : 动态内容是否正确编码 是否区分HTML、JS、CSS等上下文 身份认证 : 密码存储是否使用强哈希 会话管理是否安全 访问控制 : 是否实施最小权限原则 是否进行服务端权限检查 错误处理 : 是否泄露敏感信息 是否使用自定义错误页面 六、总结与最佳实践 6.1 审计经验总结 不要过度依赖工具,人工分析必不可少 关注框架的错误配置和安全特性禁用 特别注意业务逻辑中的安全缺陷 跟踪数据从入口到最终使用的完整流程 6.2 安全开发建议 采用安全编码规范 实施SDL流程 定期进行安全培训 建立代码审查制度 6.3 持续学习资源 OWASP Top 10 CWE/SANS Top 25 框架官方安全文档 安全社区漏洞分享