当前位置:首页 » 《随便一记》 » 正文

CVE-2022-40664 ShiroFilter1.7和1.10对于forward请求的处理

23 人参与  2022年10月18日 09:36  分类 : 《随便一记》  评论

点击全文阅读


近期Shiro修复了一个漏洞,1.10.0之前的版本在请求forward时不进行拦截鉴权

 

如下测试代码,方法1不需要权限,方法2配置了authc,方法1转发方法2,则可以绕过方法2的鉴权

Controller

 ShiroConfig

 

目录

ShiroFilter在两个版本间的代码区别

1.7版本

1.10版本

SpringBoot对与外部Filter的集成过程

FilterRegistrationBean执行流程

总结


ShiroFilter在两个版本间的代码区别

1.7在forward请求时会跳过,1.10默认情况下forward请求也会走过滤

1.7版本

org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter shiro-web.jar

在该请求处理过第一次后,为请求添加了属性shiroFilter.FILTERED=true, 在第二次forward请求进来时会进到第一个if跳过本Filter的执行

 

1.10版本

org.apache.shiro.web.servlet.OncePerRequestFilter#doFilter shiro-web.jar

增加了一个属性filterOncePerRequest来判断是否需要每个请求都进行过滤,如果为true则不过滤forward请求,如果为false每个请求都会走一遍鉴权

 filterOncePerRequest属性在1.10之后新增,默认是false,也就是过滤forward

 

虽然shiro本身支持了forward过滤,但是在springBoot下使用shiro1.10新特性,不只是改个版本号

SpringBoot对与外部Filter的集成过程

org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#onRefresh

--》org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#createWebServer

--》org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#getSelfInitializer

--》org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext#selfInitialize

在这里获取各种初始化类,调用onStartup方法进行web服务器的初始化

 getServletContextInitializerBeans方法返回是一个集合类,查找容器中所有的Filter,Servlet,ServletContextInitializer等等相关的初始化bean

 addServletContextInitializerBeans(beanFactory);

查询容器中所有ServletContextInitializer实现类放入this.initializer集合中,实现类列表如下, 可以看到Filter相关的实现类是FilterRegistrationBean,先忽略看圈内的第二个方法

 addAdaptableBeans(beanFactory);

获取容器中Servlet/Filter类型的bean,将其作为RegistrationBean放入this.initializer集合,对于Filter来说,就是查询容器所有Filter类型的bean,封装为FilterRegistrationBean放入this.initializer集合

 

所以由上边两拨代码可知,可以有以下几种方式引入ShiroFilter(应该还有其他方式@WebFilter/DelegatingFilterProxy等 ,这里不涉及,咱忽略)

1、ShiroFilterFactoryBean

 如上配置之后,ShiroFilter作为bean被加载到spring容器,再由addAdaptableBeans(beanFactory);方法将其封装为FilterRegistrationBean,调用onStartup方法加载到Tomcat中

2、FilterRegistrationBean

直接向spring容器注入FilterRegistrationBean

 

FilterRegistrationBean执行流程

顶层父类继承自ServletContextInitializer,自然从onStartup方法看起

 先将filter放入servlet容器,再进行配置

 将filter加入Tomcat的servletContext

配置Filter

我们重点看下边代码开头的DispatcherType配置,如果我们没有自己在FilterRegistrationBean配置的话,默认情况下ShiroFilter是只会处理REQUEST类型的请求,因为ShiroFilter继承的不是org.springframework.web.filter.OncePerRequestFilter

@Overrideprotected void configure(FilterRegistration.Dynamic registration) {super.configure(registration);        // 这里DispatcherType表示请求类型        // 首先设置Filter可以处理的请求类型EnumSet<DispatcherType> dispatcherTypes = this.dispatcherTypes;        // 如果没有自己设置DispatcherTypeif (dispatcherTypes == null) {T filter = getFilter();            // 如果filter类型是org.springframework.web.filter.OncePerRequestFilter,则可以处理全部请求类型if (ClassUtils.isPresent("org.springframework.web.filter.OncePerRequestFilter",filter.getClass().getClassLoader()) && filter instanceof OncePerRequestFilter) {dispatcherTypes = EnumSet.allOf(DispatcherType.class);}else {                // 否则只能处理REQUEST类型的请求dispatcherTypes = EnumSet.of(DispatcherType.REQUEST);}}Set<String> servletNames = new LinkedHashSet<>();for (ServletRegistrationBean<?> servletRegistrationBean : this.servletRegistrationBeans) {servletNames.add(servletRegistrationBean.getServletName());}servletNames.addAll(this.servletNames);if (servletNames.isEmpty() && this.urlPatterns.isEmpty()) {registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter, DEFAULT_URL_MAPPINGS);}else {if (!servletNames.isEmpty()) {registration.addMappingForServletNames(dispatcherTypes, this.matchAfter,StringUtils.toStringArray(servletNames));}if (!this.urlPatterns.isEmpty()) {registration.addMappingForUrlPatterns(dispatcherTypes, this.matchAfter,StringUtils.toStringArray(this.urlPatterns));}}}

 注:ShiroFilter继承的也叫OncePerRequestFilter,同名,一个是spring的,一个是shiro的

 

在文章头的测试用例中forward转发开始后会进入如下方法,将当前请求路径改成转发路径和请求类型改为FORWARD

org.apache.catalina.core.ApplicationDispatcher#doForward

最终进入如下方法重新进行Filter过滤和Servlet处理

org.apache.catalina.core.ApplicationDispatcher#invoke

 在内部创建Filter链时,会先查询当前请求的Dispatcher_type,当前forward请求为FORWARD,然后在filter中查询能处理该请求的Filter组成链

 

 

总结

SpringBoot集成ShiroFilter时,默认情况下ShiroFilter不拦截Forward或者Include请求,如果在SpringBoot下使用要对Forward请求拦截鉴权,不仅需要将shiro-spring版本升级到1.10.0,而且需要手动配置FilterRegistrationBean的DispatcherType

 


点击全文阅读


本文链接:http://zhangshiyu.com/post/45314.html

<< 上一篇 下一篇 >>

  • 评论(0)
  • 赞助本站

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

关于我们 | 我要投稿 | 免责申明

Copyright © 2020-2022 ZhangShiYu.com Rights Reserved.豫ICP备2022013469号-1