java代码审计手书(一)
字数 1594 2025-08-27 12:33:43
Java代码审计手书 - 安全漏洞与修复指南
1. 伪随机数生成器漏洞
漏洞特征
- PREDICTABLE_RANDOM:在关键安全场景使用可预测随机数会导致严重漏洞
- 影响场景:
- CSRF token生成
- 密码重置token
- 其他包含秘密的信息
有漏洞代码
String generateSecretToken() {
Random r = new Random();
return Long.toHexString(r.nextLong());
}
修复方案
import org.apache.commons.codec.binary.Hex;
String generateSecretToken() {
SecureRandom secRandom = new SecureRandom();
byte[] result = new byte[32];
secRandom.nextBytes(result);
return Hex.encodeHexString(result);
}
Scala版本修复
import java.security.SecureRandom
def generateSecretToken() {
val rand = new SecureRandom()
val value = Array.ofDim[Byte](16)
rand.nextBytes(value)
return value.map("%02x" format _).mkString
}
2. Servlet输入验证漏洞
漏洞类型
-
SERVLET_PARAMETER:未验证的GET/POST参数
- 可能导致SQL注入、目录穿越、命令注入、XSS等
-
SERVLET_CONTENT_TYPE:未验证的Content-Type头
-
SERVLET_SERVER_NAME:未验证的Hostname头
ServletRequest.getServerName()和HttpServletRequest.getHeader("Host")都可能被篡改
-
SERVLET_SESSION_ID:未验证的session cookie值
HttpServletRequest.getRequestedSessionId()返回的JSESSIONID可能被伪造
-
SERVLET_QUERY_STRING:未验证的查询字符串
HttpServletRequest.getQueryString()获取的值不可信
-
SERVLET_HEADER:未验证的HTTP头
- 包括Referer、User-Agent等都可能被伪造
3. 路径穿越漏洞
文件读取漏洞(PATH_TRAVERSAL_IN)
有漏洞代码
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", image); // 漏洞点
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
修复方案
import org.apache.commons.io.FilenameUtils;
@GET
@Path("/images/{image}")
@Produces("images/*")
public Response getImage(@javax.ws.rs.PathParam("image") String image) {
File file = new File("resources/images/", FilenameUtils.getName(image)); // 修复
if (!file.exists()) {
return Response.status(Status.NOT_FOUND).build();
}
return Response.ok().entity(new FileInputStream(file)).build();
}
Scala版本修复
import org.apache.commons.io.FilenameUtils;
def getWordList(value:String) = Action {
val filename = "public/lists/" + FilenameUtils.getName(value)
if (!Files.exists(Paths.get(filename))) {
NotFound("File not found")
} else {
val result = Source.fromFile(filename).getLines().mkString // 修复
Ok(result)
}
}
4. 命令注入漏洞
有漏洞代码
import java.lang.Runtime;
Runtime r = Runtime.getRuntime();
r.exec("/bin/sh -c some_tool" + input);
Scala版本漏洞
def executeCommand(value:String) = Action {
val result = value.!
Ok("Result:\n"+result)
}
5. 加密相关漏洞
弱哈希算法
- WEAK_MESSAGE_DIGEST_MD5:MD2/MD4/MD5已不安全
- WEAK_MESSAGE_DIGEST_SHA1:SHA-1已不安全
有漏洞代码
MessageDigest md5Digest = MessageDigest.getInstance("MD5");
md5Digest.update(password.getBytes());
byte[] hashValue = md5Digest.digest();
修复方案(PBKDF2)
public static byte[] getEncryptedPassword(String password, byte[] salt)
throws NoSuchAlgorithmException, InvalidKeySpecException {
KeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 4096, 256 * 8);
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
return f.generateSecret(spec).getEncoded();
}
SSL/TLS配置问题
- WEAK_TRUST_MANAGER:接受任何证书的TrustManager
- WEAK_HOSTNAME_VERIFIER:接受任何证书的HostnameVerifier
- DEFAULT_HTTP_CLIENT:与TLS 1.2不兼容的DefaultHttpClient
- SSL_CONTEXT:使用弱SSL配置
HttpClient修复方案
// 方案1
HttpClient client = new SystemDefaultHttpClient();
// 方案2
HttpClient client = HttpClientBuilder.create().useSystemProperties().build();
// 方案3
HttpClient client = HttpClients.createSystem();
SSLContext修复方案
SSLContext.getInstance("TLS"); // 替代SSL
6. 其他重要漏洞
文件上传漏洞(FILE_UPLOAD_FILENAME)
- 客户端可能通过篡改文件名访问系统任意文件
- 例如:".config/overide_file"或"shell.jsp\u0000expected.gif"
正则表达式DoS(REDOS)
- 某些正则表达式写法会导致拒绝服务攻击
- 例如:
^(a+)+$对输入"aaaaaaaaaaaaaaaaX"会分析65536种路径
框架端点安全
- JAXRS_ENDPOINT:JAX-RS REST服务端点
- TAPESTRY_ENDPOINT:Tapestry页面
- WICKET_ENDPOINT:Wicket web页面
最佳实践总结
- 输入验证:永远不要信任任何客户端输入
- 加密安全:
- 使用PBKDF2等强哈希算法
- 避免MD5/SHA1等弱算法
- 正确配置SSL/TLS
- 随机数生成:使用SecureRandom替代Random
- 文件操作:
- 使用FilenameUtils处理文件名
- 防止路径穿越
- 会话管理:
- 不要记录session ID
- 不要将敏感数据存储在cookie中
- 命令执行:避免直接拼接用户输入执行命令
参考资源
- OWASP各类备忘单(Cheat Sheet)
- NIST加密算法建议
- CWE漏洞分类
- WASC威胁分类