Apache Shiro before 1.10.0, Authentication Bypass Vulnerability in Shiro when forwarding or including via RequestDispatcher.1
| 字段 | 内容 |
|---|---|
| CVE 编号 | CVE-2022-40664 / CVE-2022-32532 |
| 漏洞等级 | 🔴 高危 |
| 漏洞类型 | 认证绕过 (Authentication Bypass) |
| 影响版本 | Apache Shiro < 1.10.0 |
| 漏洞成因 | RequestDispatcher forward/include 请求未正确纳入 Shiro Filter 的权限校验范围 |
| 修复版本 | Apache Shiro 1.10.0 |
核心原理: Shiro 的
PathMatchingFilter在处理FORWARD和INCLUDE类型的 Dispatcher 请求时,未正确执行路径匹配和权限校验,导致通过RequestDispatcher.forward()转发的请求可以绕过 Shiro 配置的认证/授权 Filter。
GET /admin/auth_pass HTTP/1.1
Host: target.com
预期行为:Shiro 拦截该请求,返回 401 或重定向到登录页面(因为 /admin/** 路径需要认证)。
GET /admin/auth HTTP/1.1
Host: target.com
通过 RequestDispatcher.forward() 将请求转发到 /admin/auth,Shiro 的 Filter 链可能不会对 forward 请求执行权限校验,从而绕过认证。
GET /admin/auth HTTP/1.1
Host: target.com
Token: 4ra1n
@RequestMapping("/admin/{value}")
public String CVE_2022_40664_bypass(
@PathVariable String value,
HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
System.out.println("=========== /admin" + request.getRequestURI() + "/ ===========");
// 方式1: forward(漏洞利用点)
// request.getRequestDispatcher("/admin/auth").forward(request, response);
// 方式2: return forward 字符串
// return "forward:" + request.getRequestURI();
// 方式3: redirect(不会触发漏洞)
response.sendRedirect("/admin/auth");
return ("Redirect:/admin/auth");
}
关键区别:
redirect是客户端行为(302 响应),浏览器会发起新的 GET 请求,Shiro 会正常拦截;而forward是服务端行为,请求在同一容器内转发,Shiro 的 Filter 链可能不会对 forward 类型的 Dispatcher 请求执行权限校验。
// 方式1: 直接使用 RequestDispatcher.forward()
request.getRequestDispatcher("/admin/auth").forward(request, response);
// 方式2: Spring MVC return forward 字符串
return "forward:" + request.getRequestURI();
// 方式3: Spring MVC <jsp:forward> 标签(JSP 页面中)
// <jsp:forward page="/admin/auth" />
在 Shiro 1.10.0 中,可以通过配置 ShiroFilterConfiguration 并注册自定义 MyShiroFilterFactoryBean 来修复此漏洞:
@Bean
public MyShiroFilterFactoryBean filterRegBean(SecurityManager securityManager) throws Exception {
// CVE-2022-40664
// fixed conf
ShiroFilterConfiguration conf = new ShiroFilterConfiguration();
conf.setFilterOncePerRequest(false);
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setShiroFilterConfiguration(conf);
AbstractShiroFilter filter = shiroFilterFactoryBean.getObject();
MyShiroFilterFactoryBean reg = new MyShiroFilterFactoryBean();
reg.setFilter(filter);
reg.addUrlPattern("/*");
reg.setName("shiroFilter");
reg.setSecurityManager(securityManager);
reg.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
// fixed conf end.
return reg;
}
| 配置项 | 作用 | 说明 |
|---|---|---|
setFilterOncePerRequest(false) |
允许 Filter 在同一请求中多次执行 | 确保 forward 请求也会经过 Filter 链 |
setDispatcherTypes(EnumSet.allOf(DispatcherType.class)) |
注册所有 Dispatcher 类型 | 包括 FORWARD、INCLUDE、ERROR、ASYNC 等类型 |
修复效果: 通过将
DispatcherType.FORWARD和DispatcherType.INCLUDE纳入 Filter 的处理范围,确保 forward/include 请求也会经过 Shiro 的权限校验 Filter 链,从而修复认证绕过漏洞。
| 层级 | 问题 |
|---|---|
| 设计层 | Shiro 的 Filter 注册默认仅处理 REQUEST 类型的 Dispatcher,未覆盖 FORWARD 和 INCLUDE |
| 代码层 | PathMatchingFilter 在处理非 REQUEST 类型的 Dispatcher 时跳过了路径匹配和权限校验 |
| 配置层 | 默认的 ShiroFilterFactoryBean 未将 FORWARD 等 Dispatcher 类型注册到 Filter 中 |
| 维度 | 影响 |
|---|---|
| 机密性 | 🔴 高 — 绕过认证后可访问受保护的敏感资源 |
| 完整性 | 🟠 中 — 可能执行未授权的写操作 |
| 可用性 | 🔵 低 — 不直接影响系统可用性 |
| 业务影响 | 🔴 高 — 所有基于 Shiro 的权限校验均可被绕过 |
ShiroFilterConfiguration 配置将 FORWARD 和 INCLUDE 类型纳入 Filter 处理范围。RequestDispatcher.forward() 和 include() 的地方,确认是否涉及敏感路径。