Java安全编码规范 (Java Secure Coding Standards)
分类: SDL规范文档 · 阅读时间: 约10分钟 · 最后更新: 2026-04-05

1. 概述

本规范针对 Java/JVM 生态系统, 提供具体的安全编码规则和代码示例。内容涵盖 SQL 注入防护、XSS 防御、反序列化安全、密码学 API 使用和文件 I/O 安全五个关键领域。所有规则基于安全编码总则中的通用原则, 并结合 Java 语言特性给出可操作的编码指导。

版本说明
本规范基于 Java 17 LTS 及以上版本。部分 API (如 java.security 包的增强) 可能不适用于旧版本。

2. SQL注入防护

2.1 使用 PreparedStatement

SQL注入仍然是 Web 应用中最常见的高危漏洞之一。Java 中防御 SQL 注入的首要规则是: 永远使用 PreparedStatement 进行参数化查询, 禁止字符串拼接构造 SQL。

错误示例 (存在SQL注入):

// 危险: 直接拼接用户输入
String query = "SELECT * FROM users WHERE username = '" + userInput + "'";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(query);

正确示例:

// 安全: 使用参数化查询
String query = "SELECT * FROM users WHERE username = ?";
PreparedStatement pstmt = connection.prepareStatement(query);
pstmt.setString(1, userInput);
ResultSet rs = pstmt.executeQuery();

2.2 ORM框架的安全使用

使用 Hibernate/JPA 时, 同样需要避免 HQL/JPQL 字符串拼接:

// 危险: HQL拼接
String hql = "FROM User WHERE name = '" + name + "'";

// 安全: 使用命名参数
String hql = "FROM User WHERE name = :name";
Query query = session.createQuery(hql);
query.setParameter("name", name);

3. XSS防御

3.1 输出编码

在将用户输入渲染到 HTML 页面时, 必须进行上下文感知的输出编码。推荐使用 OWASP Java Encoder 库:

import org.owasp.encoder.Encode;

// HTML Context
String safeHtml = Encode.forHtml(userInput);

// JavaScript Context
String safeJs = Encode.forJavaScript(userInput);

// URL Parameter Context
String safeUrl = Encode.forUriComponent(userInput);

3.2 Content Security Policy

在 Servlet Filter 或 Spring Interceptor 中配置 CSP 头:

response.setHeader("Content-Security-Policy",
    "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'");
框架选择
使用 Thymeleaf 等现代模板引擎时, 默认输出编码已启用。但使用 th:utext (unescaped text) 时编码会被禁用, 应仅在确认内容安全时使用。

4. 反序列化安全

4.1 风险背景

Java 原生反序列化 (ObjectInputStream) 是已知的高危攻击面。攻击者可以构造恶意序列化数据, 在反序列化过程中触发任意代码执行 (Remote Code Execution)。Apache Commons Collections、Spring Framework 等常用库中均发现过可利用的 gadget chain。

4.2 防御策略

首选方案: 避免 Java 原生反序列化

  • 使用 JSON (Jackson, Gson) 或 Protocol Buffers 替代 Java 原生序列化
  • API 接口使用 JSON/XML 而非 Java 序列化格式

不得不使用时: 白名单过滤

// 使用 ObjectInputFilter (Java 9+)
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(
    "com.myapp.dto.*;!*"  // 仅允许指定包下的类
);
ObjectInputStream ois = new ObjectInputStream(inputStream);
ois.setObjectInputFilter(filter);

4.3 依赖管理

定期更新依赖, 移除或升级已知存在反序列化漏洞的库版本。使用 SCA 工具 (如 OWASP Dependency-Check) 自动检测易受攻击的依赖。

5. 密码学API使用

5.1 对称加密

// 推荐: AES-256-GCM (提供加密 + 完整性保护)
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
SecretKeySpec keySpec = new SecretKeySpec(keyBytes, "AES");
GCMParameterSpec gcmSpec = new GCMParameterSpec(128, ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, keySpec, gcmSpec);

禁止使用的算法和模式:

  • DES, 3DES - 密钥长度不足
  • AES/ECB/* - ECB 模式不提供语义安全性
  • AES/CBC/PKCS5Padding - 容易受到 Padding Oracle 攻击 (若未配合 HMAC 使用)

5.2 密码哈希

// 密码存储: 使用 bcrypt (推荐 Spring Security 的实现)
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);
String hashed = encoder.encode(rawPassword);
boolean matches = encoder.matches(rawPassword, hashed);

5.3 安全随机数

// 安全场景必须使用 SecureRandom
SecureRandom random = SecureRandom.getInstanceStrong();
byte[] token = new byte[32];
random.nextBytes(token);

// 禁止使用 java.util.Random 或 Math.random() 生成安全相关的随机值

6. 文件I/O安全

6.1 路径遍历防护

当文件路径包含用户输入时, 必须防止路径遍历攻击:

// 危险: 直接使用用户输入构造路径
File file = new File("/uploads/" + userFileName);

// 安全: 规范化路径后验证
Path basePath = Paths.get("/uploads").toRealPath();
Path targetPath = basePath.resolve(userFileName).normalize().toRealPath();
if (!targetPath.startsWith(basePath)) {
    throw new SecurityException("Path traversal detected");
}

6.2 临时文件安全

// 使用安全的临时文件创建方式
Path tempFile = Files.createTempFile("prefix_", ".tmp");
// 设置仅所有者可读写
Set<PosixFilePermission> perms = PosixFilePermissions.fromString("rw-------");
Files.setPosixFilePermissions(tempFile, perms);

6.3 资源释放

使用 try-with-resources 确保文件句柄和数据库连接等资源正确释放, 避免资源泄露导致的拒绝服务:

try (BufferedReader reader = Files.newBufferedReader(path)) {
    // 处理文件内容
} // 自动关闭, 即使发生异常

7. 小结

Java 安全编码的核心在于: 参数化查询防 SQL 注入, 输出编码防 XSS, 避免原生反序列化, 使用标准密码学 API, 以及严格的文件路径验证。建议将这些规则集成到代码审查 Checklist 和 SAST 工具规则集中, 实现自动化的安全编码合规检查。

张志远 (Zhang Zhiyuan)
Java Security Specialist
Java安全编码专家, 深耕 JVM 安全领域多年。擅长 Java 反序列化漏洞分析、Spring 安全框架架构设计, 参与维护多个开源安全组件。在 BlackHat、KCon 等安全会议上分享过 Java 安全研究成果。