getRequestURl导致的安全鉴权问题
字数 1870 2025-08-20 18:18:15
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)结尾来决定是否放行请求。
漏洞代码示例:
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可能绕过认证检查。
防御建议
-
使用getServletPath()代替getRequestURL()/getRequestURI()
getServletPath()返回的路径通常已经过规范化处理,不包含特殊字符
-
规范化路径后再检查
- 使用
normalize()方法处理路径 - 示例:
String path = request.getServletPath(); path = new File(path).getCanonicalPath();
- 使用
-
严格匹配而非部分匹配
- 尽可能使用
equals()而非endsWith()或startsWith() - 如需使用部分匹配,应先规范化路径
- 尽可能使用
-
结合多种检查方法
- 同时检查
getServletPath()和getRequestURI() - 验证路径是否符合预期格式
- 同时检查
-
使用框架提供的安全机制
- 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()方法获取请求路径可能导致安全鉴权被绕过,因为:
- 这些方法返回的路径包含特殊字符
- 与
endsWith()、startsWith()或indexOf()等方法结合使用时容易产生逻辑漏洞 - 攻击者可以通过添加特殊字符(
;,.,/等)绕过检查
最佳实践:
- 优先使用
getServletPath()获取路径 - 必须使用
getRequestURI()时应先规范化路径 - 避免仅依赖部分字符串匹配进行安全决策
- 结合多种检查方法提高安全性
通过正确理解这些方法的差异并采用防御性编程技术,可以有效防止此类安全绕过问题。