Java代码审计-第一篇Spring应用程序架构审计要点
【Java代码审计 | 第一篇】Spring应用程序架构审计要点
未经许可,不得转载。
在开展Java代码审计之前,需先夯实相关基础知识,以确保审计过程更加高效和精准。
请同时参考:
Spring应用程序分层架构
Spring 是一个功能强大的 Java 开源框架,主要用于简化 Java 企业级应用开发。它提供了依赖注入(DI)、面向切面编程(AOP)、事务管理等核心特性,并支持集成各种 Java 技术(如 JDBC、JPA、Spring MVC)。Spring 通过 IoC(控制反转)容器管理对象生命周期,减少了代码耦合,提高了开发效率。
Spring 与 Java 的关系密切,它基于 Java 语言构建,广泛应用于 Java Web 开发、微服务架构(如 Spring Boot 和 Spring Cloud),成为 Java 生态中最主流的开发框架之一。
Spring 适用于大规模、细粒度控制的企业级开发,Spring Boot 更适合快速开发、微服务架构。
1. 表现层(View 层)
定义 :处理用户界面展示,常使用JSP、Thymeleaf、Freemarker等模板引擎
核心组件 :
- 模板文件(.jsp/.html)
- 视图解析器(ViewResolver)
- 前端控制器(DispatcherServlet)
审计要点 :
<!-- 漏洞示例:未转义的XSS漏洞 -->
<p>${userInput}</p> <!-- 危险写法 -->
<p th:text="${userInput}"></p> <!-- 安全写法 -->
- 模板引擎是否开启自动HTML转义
- 动态内容输出时是否强制使用安全输出语法
- 客户端渲染(如Vue/React)与服务器端渲染的混合使用场景
2. 接口层(API 层)
定义
:提供RESTful/SOAP等API接口,使用
@RestController
标注
典型特征 :
- 接口响应格式(JSON/XML)
- 统一状态码管理(如200/401/500)
审计要点 :
@GetMapping("/user")
public User getUser(@RequestParam String id) { // 未经验证的参数
return userService.findById(id);
}
- 接口鉴权缺失(如未使用
@PreAuthorize
) - 敏感数据未脱敏(如密码字段返回给前端)
- 未限制HTTP方法(如PUT/DELETE权限控制)
3. 控制器层(Controller 层)
核心组件
:
@Controller
、
@RequestMapping
处理流程 :
- 接收HTTP请求参数
- 调用Service层处理业务
- 返回视图或数据模型
审计要点 :
@RequestMapping("/download")
public void downloadFile(String filename, HttpServletResponse response) {
File file = new File("/uploads/" + filename); // 路径遍历漏洞风险
// ...
}
- 参数绑定漏洞(如
@RequestParam
未校验格式) - 未处理文件上传大小限制(导致DoS攻击)
- 重定向未校验目标地址(开放重定向漏洞)
4. 业务逻辑层(Service 层)
核心组件
:
@Service
注解类
职责 :
- 实现核心业务规则
- 事务管理(
@Transactional
)
审计示例 :
@Service
public class PaymentService {
public void transfer(Account from, Account to, BigDecimal amount) {
from.withdraw(amount); // 未加事务锁可能导致并发问题
to.deposit(amount);
}
}
审计要点 :
- 业务规则绕过(如支付金额负数校验缺失)
- 事务未处理回滚(如数据库异常后数据不一致)
- 循环依赖导致的空指针异常
5. 数据访问层(DAO 层 / Repository 层)
技术栈 :JDBC、JPA、MyBatis
核心组件 :
@Repository
注解类- JpaRepository接口实现
漏洞示例 :
@Query("SELECT u FROM User u WHERE u.username = '" + username + "'") // SQL注入风险
User findByUsername(String username);
审计要点 :
- 动态SQL拼接(MyBatis中
${}
误用) - JPA方法名注入(如
findByUsername
参数未过滤) - 连接池配置泄露(如未加密数据库密码)
6. 模型层(Model 层)
组成
:POJO类(如
User.java
)、DTO、VO
审计关注点 :
public class User {
@Size(min=6, max=20)
private String password; // 长度校验但未限制复杂度
}
- 数据验证注解(如
@NotNull
、@Pattern
)的完整性 - 敏感字段(如密码)是否标记为
@Transient
避免持久化 - DTO与实体类转换时的属性拷贝漏洞
7. 配置层(Configuration 层)
配置文件
:
application.properties
、
@Configuration
类
关键配置项 :
# 安全风险示例:关闭CSRF保护
spring.security.csrf.enabled=false
审计要点 :
- CORS配置过于宽松(如
allowedOrigins=*
) - 敏感信息硬编码(数据库密码、API密钥)
- 日志级别泄露调试信息(如开启DEBUG模式)
8. 工具层(Utility 层)
常见类
:
StringUtils
、
DateUtils
、加密工具类
漏洞案例 :
public static String encrypt(String input) {
// 使用不安全的MD5哈希
return DigestUtils.md5Hex(input);
}
审计重点 :
- 弱加密算法(如DES、MD5)
- 随机数生成器(
java.util.Random
替代SecureRandom) - 反射调用未做安全限制
9. 缓存层(Cache 层)
技术实现
:Redis、Ehcache、
@Cacheable
注解
风险场景 :
@Cacheable(value = "users", key = "#username")
public User getUser(String username) {
// 缓存未设置过期时间导致敏感数据长期驻留
}
审计要点 :
- 缓存穿透/击穿/雪崩防护机制
- 本地缓存未隔离不同用户数据
- Redis未启用SSL通信加密
10. 消息处理层(Messaging 层)
技术组件 :Kafka、RabbitMQ、JMS
漏洞示例 :
@JmsListener(destination = "orderQueue")
public void processOrder(String message) {
// 未验证消息来源,导致恶意消息注入
}
审计重点 :
- 消息消费者未做身份验证
- 消息内容未加密(敏感信息泄露)
- 死信队列未监控导致消息堆积
11. 异步层(Async 层)
实现方式
:
@Async
注解、线程池
风险代码 :
@Async
public void logAccess(String username) {
// 异步方法内未捕获异常,导致线程崩溃
accessLogService.log(username);
}
审计关注点 :
- 线程池资源耗尽(未设置合理队列大小)
- 异步任务未记录日志(难以追踪问题)
- CompletableFuture回调链中的空指针异常
12. 安全层(Security 层)
框架 :Spring Security、Shiro
配置要点 :
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/admin/**").hasRole("ADMIN") // 权限配置
.anyRequest().permitAll();
}
审计重点 :
- URL权限配置遗漏(如
/actuator/**
未保护) - 密码存储策略(是否使用BCrypt加密)
- CSRF Token未绑定到用户会话
13. 审计层(Audit 层)
实现方式
:
@Audit
注解、AOP切面
审计要求 :
@Aspect
public class AuditAspect {
@AfterReturning("execution(* com.example.service.*.*(..))")
public void logAction(JoinPoint joinPoint) {
// 未记录操作人ID和IP地址
}
}
- 关键操作日志缺失(如账户删除、权限变更)
- 日志未脱敏(记录完整信用卡号)
- 日志文件权限过宽(所有用户可读)
14. 过滤器层(Filter 层)
常见过滤器 :
- 认证过滤器(AuthenticationFilter)
- XSS防护过滤器
- 请求日志过滤器
漏洞案例 :
public class XssFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) {
// 仅过滤POST参数,遗漏GET参数
}
}
审计要点 :
- 过滤顺序错误(如先执行业务逻辑后过滤)
- 全局异常处理未覆盖过滤器中的异常
- 敏感请求头(如Authorization)未清除
15. Servlet 层
核心对象 :HttpServletRequest、HttpServletResponse
风险代码 :
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
String param = req.getParameter("input");
resp.getWriter().write(param); // 直接输出未过滤
}
审计重点 :
- 自定义Servlet的URL映射冲突
- 未禁用TRACE/TRACK方法
- 响应头未设置安全策略(如Content-Security-Policy)
底层支撑
16. JDBC
定义 :
JDBC(Java Database Connectivity)是 Java 语言用于访问关系型数据库的 API,提供了一套标准接口,使 Java 应用程序能够与不同类型的数据库(如 MySQL、PostgreSQL、Oracle)进行交互。
风险代码 :
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE id=" + input); // SQL注入
防护措施 :
- 使用PreparedStatement绑定参数
- 验证数据库连接池配置(如maxActive限制)
17. Tomcat
定义 :
Tomcat 是一个开源的 Java Servlet 容器,用于运行 Java Web 应用程序(如 JSP 和 Servlet)。它实现了 Java EE 规范(如 Servlet、JSP),并提供 HTTP 服务器功能,广泛用于 Web 应用的部署和运行。
关键配置 :
<!-- server.xml 中禁用不必要协议 -->
<Connector port="8080" protocol="HTTP/1.1"
maxThreads="200" relaxedQueryChars="[]"/> <!-- 允许特殊字符可能引发解析问题 -->
审计重点 :
- 禁用AJP协议(如不需要)
- 错误页面未泄露版本信息
- 会话固定防护配置
18. Maven
定义 :
Maven 是一个 项目管理和构建工具,用于管理 Java 项目的依赖、构建、测试和部署。它基于 pom.xml 文件定义项目结构,并通过 中央仓库(Maven Central)下载和管理第三方依赖组件,确保项目的可复现性和一致性。
依赖风险 :
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version> <!-- 已知存在反序列化漏洞 -->
</dependency>
检查项 :
- 使用
mvn dependency:tree
排查漏洞组件 - 确保SNAPSHOT版本未上线生产环境
- 仓库地址使用HTTPS协议