shiro框架Filter及其CVE-2020-1957
文章首发于TOOLS
本周检测到Apache shiro安全更新,修复安全漏洞Apache Shiro权限绕过漏洞(CVE-2020-1957)。自信分析缺陷代码及其commit后发现是url规则Filter处理时产生的漏洞,该漏洞从第一次issue、commit到第二次issue、commit(2019-03-25->2020-02-13)较长的时间才修复完成,漏洞非常简单且影响面有限,本文以CVE-2020-1957结合shiro框架Filter做简单分析。
-
* [doFilter](#dofilter)
-
* [<a href="https://github.com/apache/shiro/pull/127" target="_blank" rel="noopener">SHIRO-682](#shiro-682httpsgithubcomapacheshiropull127)</a>
本地环境
shiroConfig
1 |
|
使用LinkedHashMap
保存url、filter对应关系及url匹配、解析顺序,通过bean.setFilterChainDefinitionMap(map);
bean注入设置对应配置。
Shiro Filter
所有request访问时都会先经过shiro做认证、权限过滤,在AbstractShiroFilter.executeChain()方法根据request解析的path找到shiroFilterFactoryBean中对应的过滤规则,执行对应的Filter,最后执行业务逻辑并response。
结合源码分析request经过shiroFilter的流转处理过程
doFilter
request请求到达spring后执行对应类的doFilter,查找/创建的shiroFilter对象,调用org/apache/shiro/web/servlet/OncePerRequestFilter.class
的doFilter方法,通过request是否已有对应过滤Filter属性等通过this.doFilterInternal(request, response, filterChain);
实际调用执行/org/apache/shiro/web/servlet/AbstractShiroFilter.class
的doFilter方法,该方法主要是subject创建、执行和清理shiro需要过滤的request逻辑的实现,核心逻辑为
1 | protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse, final FilterChain chain) throws ServletException, IOException { |
调用executeChain方法,通过config找对应的执行方式然后执行getExecutionChain()方法FilterChain的返回值
1 | protected void executeChain(ServletRequest request, ServletResponse response, FilterChain origChain) throws IOException, ServletException { |
跟进getExecutionChain(),核心逻辑及两个核心方法
1 | protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) { |
- getFilterChainResolver()是在创建shiroFilter时传递的FilterChainResolver
- getChain()方法是config中配置的request url的匹配实现-pathMatcher
跟进/org/apache/shiro/web/filter/mgt/PathMatchingFilterChainResolver.class
的getChain方法,核心逻辑
1 | public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) { |
实际是一个for循环,匹配到url规则时返回对应的FilterChain给容器执行
主要匹配逻辑是在/org/apache/shiro/web/filter/PathMatchingFilter.class
的pathsMatch()中实现的
1 | protected boolean pathsMatch(String path, ServletRequest request) { |
CVE-2020-1957
看完shiro Filter的逻辑后,跟进分析下CVE-2020-1957漏洞,[CVE-2020-1957] Apache Shiro 1.5.2 released中描述是shiro框架配合Spring dynamic
controllers时存在权限绕过,如/health = authc,请求/health/可以绕过authc Filter过滤。
SHIRO-682
2019年3月25日shiro提交issue,当使用requestURI + “/“可以绕过shiro保护
2019年11月20日commit解决该issue
1 | if (requestURI != null && requestURI.endsWith(DEFAULT_PATH_SEPARATOR)) { |
即在url匹配pathsMatch时判断requestURI是否已’/‘结尾,如果是就去除’/‘
SHIRO-742
第一次修复后对requestURI没有考虑root path的情况会导致报错Can not get the NamedFilterList when request uri is "/".
2020年2月13 commit fix bug
1 | if (requestURI != null && !DEFAULT_PATH_SEPARATOR.equals(requestURI) |