getRequestURl导致的安全鉴权问题
字数 1870 2025-08-20 18:18:15

Java Web安全:getRequestURL与getRequestURI导致的鉴权绕过分析

概述

本文详细分析Java Web应用中由于使用getRequestURL()getRequestURI()方法获取请求路径而可能导致的安全鉴权绕过问题。通过对比不同URL获取方法的差异,解释攻击者如何利用这些差异绕过安全控制,并提供防御建议。

URL获取方法对比

Java Servlet API提供了几种获取请求URL的方法,它们在处理特殊字符时表现不同:

  1. getRequestURI()

    • 返回请求的URI部分(不包括协议、主机和端口)
    • 示例:对于http://example.com/path/index.html;.css,返回/path/index.html;.css
    • 特点:包含特殊字符如分号、点号等
  2. getRequestURL()

    • 返回完整的请求URL(包括协议、主机和端口,但不包括查询字符串)
    • 示例:对于上述请求,返回http://example.com/path/index.html;.css
    • 特点:同样包含特殊字符
  3. getServletPath()

    • 返回映射到Servlet的路径部分
    • 示例:对于上述请求,可能返回/path/index.html
    • 特点:通常不包含特殊字符,更"干净"

安全绕过原理

1. 基于后缀的鉴权绕过

常见漏洞场景:过滤器检查URL是否以特定后缀(如.css.js)结尾来决定是否放行请求。

漏洞代码示例:

String requestURL = req.getRequestURI();
if (requestURL.endsWith(".css")) {
    chain.doFilter(request,response);
} else {
    // 拒绝访问
}

绕过方法:

  • 在URL后添加;.css/protected/resource;.css
  • 添加/.css/protected/resource/.css
  • 添加%2e.css/protected/resource%2e.css

2. 基于路径前缀的鉴权绕过

当过滤器检查URL是否以特定路径开头时:

漏洞代码示例:

if (requestURL.startsWith("/css")) {
    chain.doFilter(request,response);
}

绕过方法:

  • 使用路径遍历:/css/../protected/resource
  • URL编码:/%63ss/protected/resource

3. equals与endsWith/startsWith的区别

  • equals:严格匹配整个字符串,难以绕过
  • endsWith/startsWith:只检查结尾/开头部分,容易通过添加特殊字符绕过
  • indexOf:检查字符串中是否包含特定子串,同样容易绕过

实际案例分析

案例1:SQL注入过滤器绕过

某系统使用getRequestURL()获取路径并检查是否包含特定关键词来过滤SQL注入:

String requestURL = req.getRequestURL().toString();
if (requestURL.indexOf("select") != -1) {
    // 阻止请求
}

绕过方法:在URL中添加;select等特殊字符,使indexOf检查失效。

案例2:Spring框架认证绕过

某Spring应用配置了对.js.css文件的免认证访问:

<security:http pattern="/**.js" security="none"/>
<security:http pattern="/**.css" security="none"/>

绕过方法:访问/admin/page;.js可能绕过认证检查。

防御建议

  1. 使用getServletPath()代替getRequestURL()/getRequestURI()

    • getServletPath()返回的路径通常已经过规范化处理,不包含特殊字符
  2. 规范化路径后再检查

    • 使用normalize()方法处理路径
    • 示例:
      String path = request.getServletPath();
      path = new File(path).getCanonicalPath();
      
  3. 严格匹配而非部分匹配

    • 尽可能使用equals()而非endsWith()startsWith()
    • 如需使用部分匹配,应先规范化路径
  4. 结合多种检查方法

    • 同时检查getServletPath()getRequestURI()
    • 验证路径是否符合预期格式
  5. 使用框架提供的安全机制

    • Spring Security等框架提供了更安全的路径匹配机制

示例代码

安全过滤器实现

public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain chain) throws ServletException, IOException {
    
    HttpServletRequest req = (HttpServletRequest) request;
    
    // 安全方式1:使用getServletPath()
    String servletPath = req.getServletPath();
    if ("/allowed/path".equals(servletPath)) {
        chain.doFilter(request, response);
        return;
    }
    
    // 安全方式2:规范化路径
    String requestURI = req.getRequestURI();
    String normalizedPath = Paths.get(requestURI).normalize().toString();
    if ("/allowed/normalized".equals(normalizedPath)) {
        chain.doFilter(request, response);
        return;
    }
    
    // 拒绝访问
    response.sendError(HttpServletResponse.SC_FORBIDDEN);
}

web.xml配置

<filter>
    <filter-name>SecurityFilter</filter-name>
    <filter-class>com.example.SecurityFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SecurityFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

总结

Java Web应用中,使用getRequestURL()getRequestURI()方法获取请求路径可能导致安全鉴权被绕过,因为:

  1. 这些方法返回的路径包含特殊字符
  2. endsWith()startsWith()indexOf()等方法结合使用时容易产生逻辑漏洞
  3. 攻击者可以通过添加特殊字符(;, ., /等)绕过检查

最佳实践

  • 优先使用getServletPath()获取路径
  • 必须使用getRequestURI()时应先规范化路径
  • 避免仅依赖部分字符串匹配进行安全决策
  • 结合多种检查方法提高安全性

通过正确理解这些方法的差异并采用防御性编程技术,可以有效防止此类安全绕过问题。

Java Web安全:getRequestURL与getRequestURI导致的鉴权绕过分析 概述 本文详细分析Java Web应用中由于使用 getRequestURL() 和 getRequestURI() 方法获取请求路径而可能导致的安全鉴权绕过问题。通过对比不同URL获取方法的差异,解释攻击者如何利用这些差异绕过安全控制,并提供防御建议。 URL获取方法对比 Java Servlet API提供了几种获取请求URL的方法,它们在处理特殊字符时表现不同: getRequestURI() 返回请求的URI部分(不包括协议、主机和端口) 示例:对于 http://example.com/path/index.html;.css ,返回 /path/index.html;.css 特点:包含特殊字符如分号、点号等 getRequestURL() 返回完整的请求URL(包括协议、主机和端口,但不包括查询字符串) 示例:对于上述请求,返回 http://example.com/path/index.html;.css 特点:同样包含特殊字符 getServletPath() 返回映射到Servlet的路径部分 示例:对于上述请求,可能返回 /path/index.html 特点:通常不包含特殊字符,更"干净" 安全绕过原理 1. 基于后缀的鉴权绕过 常见漏洞场景:过滤器检查URL是否以特定后缀(如 .css 、 .js )结尾来决定是否放行请求。 漏洞代码示例: 绕过方法: 在URL后添加 ;.css : /protected/resource;.css 添加 /.css : /protected/resource/.css 添加 %2e.css : /protected/resource%2e.css 2. 基于路径前缀的鉴权绕过 当过滤器检查URL是否以特定路径开头时: 漏洞代码示例: 绕过方法: 使用路径遍历: /css/../protected/resource URL编码: /%63ss/protected/resource 3. equals与endsWith/startsWith的区别 equals :严格匹配整个字符串,难以绕过 endsWith/startsWith :只检查结尾/开头部分,容易通过添加特殊字符绕过 indexOf :检查字符串中是否包含特定子串,同样容易绕过 实际案例分析 案例1:SQL注入过滤器绕过 某系统使用 getRequestURL() 获取路径并检查是否包含特定关键词来过滤SQL注入: 绕过方法 :在URL中添加 ;select 等特殊字符,使 indexOf 检查失效。 案例2:Spring框架认证绕过 某Spring应用配置了对 .js 和 .css 文件的免认证访问: 绕过方法 :访问 /admin/page;.js 可能绕过认证检查。 防御建议 使用getServletPath()代替getRequestURL()/getRequestURI() getServletPath() 返回的路径通常已经过规范化处理,不包含特殊字符 规范化路径后再检查 使用 normalize() 方法处理路径 示例: 严格匹配而非部分匹配 尽可能使用 equals() 而非 endsWith() 或 startsWith() 如需使用部分匹配,应先规范化路径 结合多种检查方法 同时检查 getServletPath() 和 getRequestURI() 验证路径是否符合预期格式 使用框架提供的安全机制 Spring Security等框架提供了更安全的路径匹配机制 示例代码 安全过滤器实现 web.xml配置 总结 Java Web应用中,使用 getRequestURL() 和 getRequestURI() 方法获取请求路径可能导致安全鉴权被绕过,因为: 这些方法返回的路径包含特殊字符 与 endsWith() 、 startsWith() 或 indexOf() 等方法结合使用时容易产生逻辑漏洞 攻击者可以通过添加特殊字符( ; , . , / 等)绕过检查 最佳实践 : 优先使用 getServletPath() 获取路径 必须使用 getRequestURI() 时应先规范化路径 避免仅依赖部分字符串匹配进行安全决策 结合多种检查方法提高安全性 通过正确理解这些方法的差异并采用防御性编程技术,可以有效防止此类安全绕过问题。