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输入验证漏洞

漏洞类型

  1. SERVLET_PARAMETER:未验证的GET/POST参数

    • 可能导致SQL注入、目录穿越、命令注入、XSS等
  2. SERVLET_CONTENT_TYPE:未验证的Content-Type头

  3. SERVLET_SERVER_NAME:未验证的Hostname头

    • ServletRequest.getServerName()HttpServletRequest.getHeader("Host")都可能被篡改
  4. SERVLET_SESSION_ID:未验证的session cookie值

    • HttpServletRequest.getRequestedSessionId()返回的JSESSIONID可能被伪造
  5. SERVLET_QUERY_STRING:未验证的查询字符串

    • HttpServletRequest.getQueryString()获取的值不可信
  6. 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配置问题

  1. WEAK_TRUST_MANAGER:接受任何证书的TrustManager
  2. WEAK_HOSTNAME_VERIFIER:接受任何证书的HostnameVerifier
  3. DEFAULT_HTTP_CLIENT:与TLS 1.2不兼容的DefaultHttpClient
  4. 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种路径

框架端点安全

  1. JAXRS_ENDPOINT:JAX-RS REST服务端点
  2. TAPESTRY_ENDPOINT:Tapestry页面
  3. WICKET_ENDPOINT:Wicket web页面

最佳实践总结

  1. 输入验证:永远不要信任任何客户端输入
  2. 加密安全
    • 使用PBKDF2等强哈希算法
    • 避免MD5/SHA1等弱算法
    • 正确配置SSL/TLS
  3. 随机数生成:使用SecureRandom替代Random
  4. 文件操作
    • 使用FilenameUtils处理文件名
    • 防止路径穿越
  5. 会话管理
    • 不要记录session ID
    • 不要将敏感数据存储在cookie中
  6. 命令执行:避免直接拼接用户输入执行命令

参考资源

  • OWASP各类备忘单(Cheat Sheet)
  • NIST加密算法建议
  • CWE漏洞分类
  • WASC威胁分类
Java代码审计手书 - 安全漏洞与修复指南 1. 伪随机数生成器漏洞 漏洞特征 PREDICTABLE_ RANDOM :在关键安全场景使用可预测随机数会导致严重漏洞 影响场景: CSRF token生成 密码重置token 其他包含秘密的信息 有漏洞代码 修复方案 Scala版本修复 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) 有漏洞代码 修复方案 Scala版本修复 4. 命令注入漏洞 有漏洞代码 Scala版本漏洞 5. 加密相关漏洞 弱哈希算法 WEAK_ MESSAGE_ DIGEST_ MD5 :MD2/MD4/MD5已不安全 WEAK_ MESSAGE_ DIGEST_ SHA1 :SHA-1已不安全 有漏洞代码 修复方案(PBKDF2) SSL/TLS配置问题 WEAK_ TRUST_ MANAGER :接受任何证书的TrustManager WEAK_ HOSTNAME_ VERIFIER :接受任何证书的HostnameVerifier DEFAULT_ HTTP_ CLIENT :与TLS 1.2不兼容的DefaultHttpClient SSL_ CONTEXT :使用弱SSL配置 HttpClient修复方案 SSLContext修复方案 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威胁分类