java代码审计手书(三)
字数 1588 2025-08-27 12:33:43

Java代码审计手书(三) - 安全漏洞与防御措施

1. 代码注入类漏洞

1.1 脚本引擎注入(SCRIPT_ENGINE_INJECTION)

漏洞特征:动态执行未经验证的用户输入脚本代码。

风险:恶意代码执行可导致数据泄露或任意系统指令执行。

漏洞代码

public void runCustomTrigger(String script) {
    ScriptEngineManager factory = new ScriptEngineManager();
    ScriptEngine engine = factory.getEngineByName("JavaScript");
    engine.eval(script); // 危险点
}

解决方案:使用"Cloudbees Rhino Sandbox"库安全评估JS代码

public void runCustomTrigger(String script) {
    SandboxContextFactory contextFactory = new SandboxContextFactory();
    Context context = contextFactory.makeContext();
    contextFactory.enterContext(context);
    try {
        ScriptableObject prototype = context.initStandardObjects();
        prototype.setParentScope(null);
        Scriptable scope = context.newObject(prototype);
        scope.setPrototype(prototype);
        context.evaluateString(scope,script, null, -1, null);
    } finally {
        context.exit();
    }
}

1.2 SpEL表达式注入(SPEL_INJECTION)

漏洞特征:未验证用户输入直接用于Spring表达式解析。

漏洞代码

public void parseExpressionInterface(Person personObj,String property) {
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp = parser.parseExpression(property+" == 'Albert'"); // 危险点
    StandardEvaluationContext testContext = new StandardEvaluationContext(personObj);
    boolean result = exp.getValue(testContext, Boolean.class);
}

防御措施

  • 严格验证用户输入
  • 避免用户控制表达式内容

1.3 EL表达式注入(EL_INJECTION)

漏洞特征:未验证用户输入直接用于表达式语言解析。

漏洞代码

public void evaluateExpression(String expression) {
    FacesContext context = FacesContext.getCurrentInstance();
    ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();
    ELContext elContext = context.getELContext();
    ValueExpression vex = expressionFactory.createValueExpression(elContext, expression, String.class);
    return (String) vex.getValue(elContext);
}

1.4 Seam日志注入(SEAM_LOG_INJECTION)

漏洞特征:日志API支持EL表达式解析,可能执行未预期代码。

漏洞代码

public void logUser(User user) {
    log.info("Current logged in user : " + user.getUsername()); // 危险点
}

解决方案

public void logUser(User user) {
    log.info("Current logged in user : #0", user.getUsername());
}

1.5 OGNL注入(OGNL_INJECTION)

漏洞特征:未验证用户输入直接用于OGNL表达式解析。

漏洞代码

public void getUserProperty(String property) {
    return ognlUtil.getValue("user."+property, ctx, root, String.class); // 危险点
}

2. 加密与安全传输类漏洞

2.1 不安全的加密算法

DES不安全

Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding"); // 不安全

3DES不安全

Cipher c = Cipher.getInstance("DESede/ECB/PKCS5Padding"); // 不安全

解决方案:使用AES/GCM

Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); // 安全

2.2 RSA密钥过短

漏洞特征:使用小于2048位的RSA密钥。

漏洞代码

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(512); // 不安全

解决方案

KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048); // 安全

2.3 未加密的Socket通信

漏洞代码

Socket soc = new Socket("www.google.com",80); // 明文传输
ServerSocket soc = new ServerSocket(1234); // 明文传输

解决方案

Socket soc = SSLSocketFactory.getDefault().createSocket("www.google.com", 443); // SSL加密
ServerSocket soc = SSLServerSocketFactory.getDefault().createServerSocket(1234); // SSL加密

2.4 加密完整性缺失

漏洞特征:使用不提供完整性的加密模式(CBC, OFB, CTR, ECB)。

漏洞代码

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 无完整性保护

解决方案

Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); // 提供完整性

2.5 Padding Oracle攻击

漏洞特征:使用CBC模式与PKCS5Padding易受攻击。

漏洞代码

Cipher c = Cipher.getInstance("AES/CBC/PKCS5Padding"); // 易受攻击

解决方案

Cipher c = Cipher.getInstance("AES/GCM/NoPadding"); // 安全

3. Web安全类漏洞

3.1 HTTP响应拆分(HTTP_RESPONSE_SPLITTING)

漏洞特征:未过滤CR/LF字符可能导致响应被分割。

漏洞代码

String author = request.getParameter(AUTHOR_PARAMETER);
Cookie cookie = new Cookie("author", author);
response.addCookie(cookie); // 可能注入CR/LF

3.2 未验证的重定向

漏洞特征:直接使用用户提供的URL进行重定向。

漏洞代码

// Servlet中
resp.sendRedirect(req.getParameter("redirectUrl"));

// Play Framework中
def login(redirectUrl:String) = Action {
    Redirect(url)
}

// Spring中
@RequestMapping("/redirect")
public String redirect(@RequestParam("url") String url) {
    return "redirect:" + url;
}

解决方案

  • 不接受用户输入的重定向URL
  • 使用目的地址key查询合法地址
  • 仅接受相对路径
  • URLs白名单

3.3 JSP动态包含(JSP_INCLUDE)

漏洞特征:用户可控的JSP文件包含。

漏洞代码

<jsp:include page="${param.secret_param}" />

解决方案

<c:if test="${param.secret_param == 'page1'}">
    <jsp:include page="page1.jsp" />
</c:if>

3.4 XSS漏洞

JSP中XSS

<%= taintedInput %> <!-- 不安全 -->

Servlet中XSS

resp.getWriter().write(input1); // 不安全

解决方案:使用编码输出

<%= Encode.forHtml(taintedInput) %>
resp.getWriter().write(Encode.forHtml(input1));

JSTL输出禁用XML转义

<c:out value="${param.test_param}" escapeXml="false"/> <!-- 不安全 -->

解决方案

<c:out value="${param.test_param}"/>

4. 其他安全漏洞

4.1 硬编码凭据

硬编码密码

private String SECRET_PASSWORD = "letMeIn!";
Properties props = new Properties();
props.put(Context.SECURITY_CREDENTIALS, "p@ssw0rd");

硬编码密钥

byte[] key = {1, 2, 3, 4, 5, 6, 7, 8};
SecretKeySpec spec = new SecretKeySpec(key, "AES");

4.2 不安全的哈希比较

漏洞特征:使用equals()比较哈希值可能泄露信息。

漏洞代码

if(userInput.equals(actualHash)) { ... } // 不安全

解决方案

if(MessageDigest.isEqual(userInput.getBytes(),actualHash.getBytes())) { ... }

4.3 坏的十六进制转换

漏洞特征:使用Integer.toHexString()可能导致转换错误。

漏洞代码

stringBuilder.append(Integer.toHexString(b & 0xFF)); // 可能出错

解决方案

stringBuilder.append(String.format("%02X", b));

4.4 XMLDecoder反序列化

漏洞特征:XMLDecoder可执行任意方法调用。

漏洞代码

XMLDecoder d = new XMLDecoder(in);
Object result = d.readObject(); // 危险

解决方案:避免使用XMLDecoder解析不受信任数据。

4.5 固定IV

漏洞特征:使用静态初始化向量(IV)。

漏洞代码

private static byte[] IV = new byte[16] {(byte)0,(byte)1,(byte)2,...};
IvParameterSpec ivSpec = new IvParameterSpec(IV);

解决方案:每次生成随机IV

byte[] iv = new byte[16];
new SecureRandom().nextBytes(iv);
IvParameterSpec ivSpec = new IvParameterSpec(iv);

5. 最佳实践总结

  1. 输入验证:对所有用户输入进行严格验证
  2. 安全编码
    • 避免动态执行用户提供的代码
    • 使用安全的加密算法和足够长的密钥
    • 避免硬编码凭据
  3. 输出编码:对所有动态输出进行适当的编码
  4. 安全传输:始终使用加密通信(SSL/TLS)
  5. 日志安全:过滤日志中的CRLF字符和敏感信息
  6. 配置安全:确保安全配置(如ESAPI加密配置正确)
  7. 依赖管理:保持安全库和框架的最新版本

通过遵循这些安全编码实践,可以显著降低Java应用程序中的安全风险。

Java代码审计手书(三) - 安全漏洞与防御措施 1. 代码注入类漏洞 1.1 脚本引擎注入(SCRIPT_ ENGINE_ INJECTION) 漏洞特征 :动态执行未经验证的用户输入脚本代码。 风险 :恶意代码执行可导致数据泄露或任意系统指令执行。 漏洞代码 : 解决方案 :使用"Cloudbees Rhino Sandbox"库安全评估JS代码 1.2 SpEL表达式注入(SPEL_ INJECTION) 漏洞特征 :未验证用户输入直接用于Spring表达式解析。 漏洞代码 : 防御措施 : 严格验证用户输入 避免用户控制表达式内容 1.3 EL表达式注入(EL_ INJECTION) 漏洞特征 :未验证用户输入直接用于表达式语言解析。 漏洞代码 : 1.4 Seam日志注入(SEAM_ LOG_ INJECTION) 漏洞特征 :日志API支持EL表达式解析,可能执行未预期代码。 漏洞代码 : 解决方案 : 1.5 OGNL注入(OGNL_ INJECTION) 漏洞特征 :未验证用户输入直接用于OGNL表达式解析。 漏洞代码 : 2. 加密与安全传输类漏洞 2.1 不安全的加密算法 DES不安全 : 3DES不安全 : 解决方案 :使用AES/GCM 2.2 RSA密钥过短 漏洞特征 :使用小于2048位的RSA密钥。 漏洞代码 : 解决方案 : 2.3 未加密的Socket通信 漏洞代码 : 解决方案 : 2.4 加密完整性缺失 漏洞特征 :使用不提供完整性的加密模式(CBC, OFB, CTR, ECB)。 漏洞代码 : 解决方案 : 2.5 Padding Oracle攻击 漏洞特征 :使用CBC模式与PKCS5Padding易受攻击。 漏洞代码 : 解决方案 : 3. Web安全类漏洞 3.1 HTTP响应拆分(HTTP_ RESPONSE_ SPLITTING) 漏洞特征 :未过滤CR/LF字符可能导致响应被分割。 漏洞代码 : 3.2 未验证的重定向 漏洞特征 :直接使用用户提供的URL进行重定向。 漏洞代码 : 解决方案 : 不接受用户输入的重定向URL 使用目的地址key查询合法地址 仅接受相对路径 URLs白名单 3.3 JSP动态包含(JSP_ INCLUDE) 漏洞特征 :用户可控的JSP文件包含。 漏洞代码 : 解决方案 : 3.4 XSS漏洞 JSP中XSS : Servlet中XSS : 解决方案 :使用编码输出 JSTL输出禁用XML转义 : 解决方案 : 4. 其他安全漏洞 4.1 硬编码凭据 硬编码密码 : 硬编码密钥 : 4.2 不安全的哈希比较 漏洞特征 :使用equals()比较哈希值可能泄露信息。 漏洞代码 : 解决方案 : 4.3 坏的十六进制转换 漏洞特征 :使用Integer.toHexString()可能导致转换错误。 漏洞代码 : 解决方案 : 4.4 XMLDecoder反序列化 漏洞特征 :XMLDecoder可执行任意方法调用。 漏洞代码 : 解决方案 :避免使用XMLDecoder解析不受信任数据。 4.5 固定IV 漏洞特征 :使用静态初始化向量(IV)。 漏洞代码 : 解决方案 :每次生成随机IV 5. 最佳实践总结 输入验证 :对所有用户输入进行严格验证 安全编码 : 避免动态执行用户提供的代码 使用安全的加密算法和足够长的密钥 避免硬编码凭据 输出编码 :对所有动态输出进行适当的编码 安全传输 :始终使用加密通信(SSL/TLS) 日志安全 :过滤日志中的CRLF字符和敏感信息 配置安全 :确保安全配置(如ESAPI加密配置正确) 依赖管理 :保持安全库和框架的最新版本 通过遵循这些安全编码实践,可以显著降低Java应用程序中的安全风险。