Apache-shiro-权限绕过漏洞汇总
字数 1872 2025-08-10 08:29:04

Apache Shiro 权限绕过漏洞分析与防护指南

漏洞概述

Apache Shiro 是一个功能强大且易用的 Java 安全框架,提供认证、授权、加密和会话管理等功能。本文档详细分析三个 Shiro 权限绕过漏洞(CVE-2020-1957、CVE-2020-11989、CVE-2020-13933),这些漏洞都利用了 Shiro 与 Spring 框架在 URL 解析处理上的差异,导致攻击者可以绕过权限控制访问受保护资源。

漏洞详情

CVE-2020-1957

漏洞原理

  1. URL 处理流程

    • 用户请求格式:/xxx/..;/hello/aaaa
    • Shiro 处理流程:
      • WebUtils#getPathWithinApplication 调用 getRequestUri
      • getRequestUri 调用 decodeAndCleanUriString 处理 URI
      • decodeAndCleanUriString 根据 ; 截断,返回 /xxx/..
      • normalize 方法处理路径规范化(替换 ... 等)
      • 最终 Shiro 获取的路径为 /xxx/..,与权限配置 /hello/** 不匹配,绕过权限检查
    • Spring 处理流程:
      • UrlPathHelper#getPathWithinServletMapping 处理原始请求
      • 通过 request.getServletPath() 获取 /hello/aaaa
      • 最终访问到受保护资源
  2. 关键代码分析

    // WebUtils.java
    public static String getPathWithinApplication(HttpServletRequest request) {
        String contextPath = getContextPath(request);
        String requestUri = getRequestUri(request);
        if (StringUtils.startsWithIgnoreCase(requestUri, contextPath)) {
            String path = requestUri.substring(contextPath.length());
            return (StringUtils.hasText(path) ? path : "/");
        } else {
            return requestUri;
        }
    }
    
    // decodeAndCleanUriString 方法
    private static String decodeAndCleanUriString(HttpServletRequest request, String uri) {
        uri = decodeRequestString(request, uri);
        int semicolonIndex = uri.indexOf(';');
        return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
    }
    

修复方案

  • Shiro 1.5.2 版本修改了 URI 获取方式,从 getRequestURI 改为 getContextPath()getServletPath()getPathInfo() 的组合

CVE-2020-11989

漏洞原理

  1. 两种利用方式

    • 方式一:/hello/a%25%32%66a

      • Shiro 处理:
        • URL 解码一次变为 /hello/a%2fa
        • decodeRequestString 再次解码变为 /hello/a/a
        • 与权限配置 /hello/* 不匹配(* 不匹配多级路径)
      • Spring 处理为 /hello/a%2fa,匹配路由 @GetMapping("/hello/{name}")
    • 方式二:/hello/a%25%32%66a/;/test/hello/aaa(需 context-path 不为空)

      • Shiro 处理:
        • 解码后变为 /hello/a/a/
        • 根据 ; 截断变为 /hello/a/a/
        • 与权限配置不匹配
      • Spring 处理为 /test/hello/aaa
  2. 关键代码分析

    // WebUtils.java
    public static String getRequestUri(HttpServletRequest request) {
        String uri = (String) request.getAttribute(INCLUDE_REQUEST_URI_ATTRIBUTE);
        if (uri == null) {
            uri = valueOrEmpty(request.getContextPath()) + "/" + 
                  valueOrEmpty(request.getServletPath()) + 
                  valueOrEmpty(request.getPathInfo());
        }
        return normalize(decodeAndCleanUriString(request, uri));
    }
    
    // decodeRequestString 方法
    public static String decodeRequestString(HttpServletRequest request, String source) {
        String enc = determineEncoding(request);
        try {
            return URLDecoder.decode(source, enc);
        } catch (UnsupportedEncodingException ex) {
            return URLDecoder.decode(source);
        }
    }
    

修复方案

  • Shiro 1.5.3 版本:
    • 采用标准的 getServletPathgetPathInfo 进行 URI 处理
    • 取消了 URL 解码
    public static String getPathWithinApplication(HttpServletRequest request) {
        return normalize(removeSemicolon(getServletPath(request) + getPathInfo(request)));
    }
    

CVE-2020-13933

漏洞原理

  1. 利用方式

    • 请求格式:/hello/%3baaaa
    • Shiro 处理:
      • URL 解码为 /hello/;aaaa
      • removeSemicolon 根据 ; 截断,返回 /hello/
      • 与权限配置 /hello/* 不匹配
    • Spring 处理为原始路径,匹配路由
  2. 关键代码

    private static String removeSemicolon(String uri) {
        int semicolonIndex = uri.indexOf(';');
        return (semicolonIndex != -1 ? uri.substring(0, semicolonIndex) : uri);
    }
    

修复方案

  • 新增 InvalidRequestFilter 过滤器,检查特殊字符:
    private static final List<String> SEMICOLON = Collections.unmodifiableList(Arrays.asList(";", "%3b", "%3B"));
    private static final List<String> BACKSLASH = Collections.unmodifiableList(Arrays.asList("\\", "%5c", "%5C"));
    

漏洞防护建议

  1. 升级方案

    • 及时升级到最新版本 Shiro
    • CVE-2020-1957:升级至 1.5.2+
    • CVE-2020-11989:升级至 1.5.3+
    • CVE-2020-13933:升级至 1.6.0+
  2. 临时缓解措施

    • 在应用中添加过滤器,对请求路径进行严格校验
    • 禁用分号(;)和反斜杠(\)等特殊字符
    • 统一 Shiro 和 Spring 的 URL 解析逻辑
  3. 安全配置建议

    • 使用严格路径匹配模式
    • 避免使用过于宽松的通配符(如 **
    • 实施多层防御,结合框架安全机制和自定义校验

总结

这三个 Shiro 权限绕过漏洞的核心问题在于 Shiro 和 Spring 对 URL 的解析处理存在差异,攻击者利用这些差异构造特殊路径绕过权限检查。防护的关键在于:

  1. 统一 URL 解析逻辑
  2. 严格控制特殊字符处理
  3. 保持框架最新版本
  4. 实施深度防御策略

通过理解这些漏洞的原理和修复方案,开发人员可以更好地保护应用免受类似攻击。

Apache Shiro 权限绕过漏洞分析与防护指南 漏洞概述 Apache Shiro 是一个功能强大且易用的 Java 安全框架,提供认证、授权、加密和会话管理等功能。本文档详细分析三个 Shiro 权限绕过漏洞(CVE-2020-1957、CVE-2020-11989、CVE-2020-13933),这些漏洞都利用了 Shiro 与 Spring 框架在 URL 解析处理上的差异,导致攻击者可以绕过权限控制访问受保护资源。 漏洞详情 CVE-2020-1957 漏洞原理 URL 处理流程 : 用户请求格式: /xxx/..;/hello/aaaa Shiro 处理流程: WebUtils#getPathWithinApplication 调用 getRequestUri getRequestUri 调用 decodeAndCleanUriString 处理 URI decodeAndCleanUriString 根据 ; 截断,返回 /xxx/.. normalize 方法处理路径规范化(替换 .. 、 . 等) 最终 Shiro 获取的路径为 /xxx/.. ,与权限配置 /hello/** 不匹配,绕过权限检查 Spring 处理流程: UrlPathHelper#getPathWithinServletMapping 处理原始请求 通过 request.getServletPath() 获取 /hello/aaaa 最终访问到受保护资源 关键代码分析 : 修复方案 Shiro 1.5.2 版本修改了 URI 获取方式,从 getRequestURI 改为 getContextPath() 、 getServletPath() 、 getPathInfo() 的组合 CVE-2020-11989 漏洞原理 两种利用方式 : 方式一: /hello/a%25%32%66a Shiro 处理: URL 解码一次变为 /hello/a%2fa decodeRequestString 再次解码变为 /hello/a/a 与权限配置 /hello/* 不匹配( * 不匹配多级路径) Spring 处理为 /hello/a%2fa ,匹配路由 @GetMapping("/hello/{name}") 方式二: /hello/a%25%32%66a/;/test/hello/aaa (需 context-path 不为空) Shiro 处理: 解码后变为 /hello/a/a/ 根据 ; 截断变为 /hello/a/a/ 与权限配置不匹配 Spring 处理为 /test/hello/aaa 关键代码分析 : 修复方案 Shiro 1.5.3 版本: 采用标准的 getServletPath 和 getPathInfo 进行 URI 处理 取消了 URL 解码 CVE-2020-13933 漏洞原理 利用方式 : 请求格式: /hello/%3baaaa Shiro 处理: URL 解码为 /hello/;aaaa removeSemicolon 根据 ; 截断,返回 /hello/ 与权限配置 /hello/* 不匹配 Spring 处理为原始路径,匹配路由 关键代码 : 修复方案 新增 InvalidRequestFilter 过滤器,检查特殊字符: 漏洞防护建议 升级方案 : 及时升级到最新版本 Shiro CVE-2020-1957:升级至 1.5.2+ CVE-2020-11989:升级至 1.5.3+ CVE-2020-13933:升级至 1.6.0+ 临时缓解措施 : 在应用中添加过滤器,对请求路径进行严格校验 禁用分号( ; )和反斜杠( \ )等特殊字符 统一 Shiro 和 Spring 的 URL 解析逻辑 安全配置建议 : 使用严格路径匹配模式 避免使用过于宽松的通配符(如 ** ) 实施多层防御,结合框架安全机制和自定义校验 总结 这三个 Shiro 权限绕过漏洞的核心问题在于 Shiro 和 Spring 对 URL 的解析处理存在差异,攻击者利用这些差异构造特殊路径绕过权限检查。防护的关键在于: 统一 URL 解析逻辑 严格控制特殊字符处理 保持框架最新版本 实施深度防御策略 通过理解这些漏洞的原理和修复方案,开发人员可以更好地保护应用免受类似攻击。