这个鉴权到底能不能绕
字数 1351 2025-08-09 13:33:44

Spring鉴权绕过技术分析与防御指南

概述

本文详细分析Spring框架中两种常见的鉴权绕过技术,包括URL编码绕过和路径穿越绕过,并提供了相应的防御建议。文章基于实际漏洞分析,深入探讨了不同Spring版本下的鉴权机制差异。

第一种绕过:URL编码绕过

漏洞场景

当鉴权逻辑使用request.getRequestURI()并检查路径中是否包含特定字符串时:

String requestPath = request.getRequestURI();
if (requestPath.indexOf("/user/") != -1) {
    // 鉴权逻辑
}

绕过方法

  1. 使用BurpSuite拦截请求
  2. 对关键字符进行URL编码(如将"r"编码为"%72")
  3. 发送编码后的请求(如/use%72/show

技术原理

  1. Spring的DispatcherServlet处理请求时会调用UrlPathHelper#decodeAndCleanUriString方法
  2. 该方法对URI进行三步处理:
    • 移除分号内容(removeSemicolonContent)
    • URL解码(decodeRequestString)
    • 清理路径(getSanitizedPath)
  3. 拦截器获取的是编码前的URI,而Spring处理后是解码后的URI,导致匹配失败

影响范围

所有Spring版本都存在此问题

第二种绕过:路径穿越绕过

漏洞场景

当鉴权逻辑使用request.getRequestURI()并检查路径是否以特定字符串开头时:

String requestPath = request.getRequestURI();
if (requestPath.startsWith("/anything/")) {
    // 放行
} else {
    // 鉴权
}

绕过方法

使用路径穿越技术:

/anything/../user/show

技术原理

  1. 在Spring 5.3.x以下版本中:

    • UrlPathHelper#getLookupPathForRequest方法默认使用getPathWithinServletMapping
    • Tomcat会处理路径穿越,返回正常化的URL
    • 导致鉴权逻辑看到的路径与实际处理路径不一致
  2. 在Spring 5.3.x及以上版本中:

    • 新增了skipServletPathDetermination检查
    • 默认情况下不再使用getPathWithinServletMapping
    • 路径穿越无法生效

影响范围

仅Spring 5.3.x以下版本存在此问题

防御建议

  1. 统一路径获取方式

    • 使用request.getServletPath()而非getRequestURI()
    • 或使用Spring提供的UrlPathHelper统一处理
  2. 规范化路径比较

    • 比较前先对路径进行规范化处理
    • 使用PathPattern替代简单的字符串匹配
  3. 版本升级

    • 升级到Spring 5.3.x及以上版本
  4. 防御性编码

    // 规范化路径后再比较
    String path = new UrlPathHelper().getLookupPathForRequest(request);
    if (path.startsWith("/anything/")) {
        // 放行
    }
    
  5. 多层防御

    • 结合Servlet容器的安全约束
    • 使用Spring Security等专业安全框架

环境搭建与验证

环境准备

  1. 创建Spring Web项目

  2. 添加依赖:

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.18.RELEASE</version> <!-- 测试用版本 -->
    </dependency>
    
  3. 配置拦截器:

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        String path = request.getRequestURI();
        // 鉴权逻辑
    }
    

验证步骤

  1. 使用不同Spring版本部署
  2. 尝试两种绕过技术
  3. 观察拦截效果

总结

  1. URL编码绕过适用于所有Spring版本,防御关键是统一路径获取方式
  2. 路径穿越绕过仅影响Spring 5.3.x以下版本,升级可解决
  3. 鉴权逻辑应避免简单的字符串匹配,使用框架提供的规范化方法
  4. 专业安全框架(如Spring Security)能提供更全面的保护

通过深入理解这些绕过技术的原理,开发人员可以编写更安全的鉴权代码,有效防止未授权访问。

Spring鉴权绕过技术分析与防御指南 概述 本文详细分析Spring框架中两种常见的鉴权绕过技术,包括URL编码绕过和路径穿越绕过,并提供了相应的防御建议。文章基于实际漏洞分析,深入探讨了不同Spring版本下的鉴权机制差异。 第一种绕过:URL编码绕过 漏洞场景 当鉴权逻辑使用 request.getRequestURI() 并检查路径中是否包含特定字符串时: 绕过方法 使用BurpSuite拦截请求 对关键字符进行URL编码(如将"r"编码为"%72") 发送编码后的请求(如 /use%72/show ) 技术原理 Spring的 DispatcherServlet 处理请求时会调用 UrlPathHelper#decodeAndCleanUriString 方法 该方法对URI进行三步处理: 移除分号内容( removeSemicolonContent ) URL解码( decodeRequestString ) 清理路径( getSanitizedPath ) 拦截器获取的是编码前的URI,而Spring处理后是解码后的URI,导致匹配失败 影响范围 所有Spring版本 都存在此问题 第二种绕过:路径穿越绕过 漏洞场景 当鉴权逻辑使用 request.getRequestURI() 并检查路径是否以特定字符串开头时: 绕过方法 使用路径穿越技术: 技术原理 在Spring 5.3.x以下版本中: UrlPathHelper#getLookupPathForRequest 方法默认使用 getPathWithinServletMapping Tomcat会处理路径穿越,返回正常化的URL 导致鉴权逻辑看到的路径与实际处理路径不一致 在Spring 5.3.x及以上版本中: 新增了 skipServletPathDetermination 检查 默认情况下不再使用 getPathWithinServletMapping 路径穿越无法生效 影响范围 仅Spring 5.3.x以下版本 存在此问题 防御建议 统一路径获取方式 : 使用 request.getServletPath() 而非 getRequestURI() 或使用Spring提供的 UrlPathHelper 统一处理 规范化路径比较 : 比较前先对路径进行规范化处理 使用 PathPattern 替代简单的字符串匹配 版本升级 : 升级到Spring 5.3.x及以上版本 防御性编码 : 多层防御 : 结合Servlet容器的安全约束 使用Spring Security等专业安全框架 环境搭建与验证 环境准备 创建Spring Web项目 添加依赖: 配置拦截器: 验证步骤 使用不同Spring版本部署 尝试两种绕过技术 观察拦截效果 总结 URL编码绕过适用于所有Spring版本,防御关键是统一路径获取方式 路径穿越绕过仅影响Spring 5.3.x以下版本,升级可解决 鉴权逻辑应避免简单的字符串匹配,使用框架提供的规范化方法 专业安全框架(如Spring Security)能提供更全面的保护 通过深入理解这些绕过技术的原理,开发人员可以编写更安全的鉴权代码,有效防止未授权访问。