shiro1.6升级到1.7后的问题处理
由于shiro1.6出现了安全漏洞,需要进⾏1.7的升级
问题描述
进⾏升级后有个url突然访问不了,HTTP返回了400,Invaild Request。
接收的URL为 xxx/detail/{name}。
前端传递的地址为 xxx%2fdetail%2f%e6%88%bf%e4%ba%a7(带有中⽂,已⽤URL编码)
思路
1.
1. 看到HTTP响应400,我在想是前端参数出了什么问题吗?还是后台接收参数改动了吗?
2. 看了git记录,这边没⼈改动,那这就很灵性了,只能通过调试出哪个地⽅访问了400了,我是全局搜了⼀下代码⾥哪⾥有
400或者Invaild Request
3. 然后通过git记录发现只是升级了⼀些框架的源码,通过排除法,先最有可能出现错误的框架,这⾥是spring和shiro都回退,
发现果然是升级shiro出了问题,(把shiro回退到1.6问题就没出现)
然后就开始打断点调试
2. 先给出结论:
url带有中⽂字符shiro校验不通过
3. 排查流程
org.apache.shiro.web.filter.AccessControlFilter 校验失败了
⼦类org.apache.shiro.web.filter.InvalidRequestFilter 返回了400
这时候就要出1.7的版本,为什么会被拦截掉了。
然后调试⼀下1.6的版本为什么没出问题,⽐较类的差异,通过github直接看,或者直接修改版本IDEA⽀持⾃动反编译。
然后通过调试发现,问题出现在这⼀句PathInfo())
1.6版本是只校验了uri,uri经过了URL编码是可以通过这个⽅法的
但是1.PathInfo()是返回的URL解码过的路径,包含了中⽂,从⽅法名可以看出
containsNonAsciiCharacters(uri)这个⽅法没办法通过校验
4. 解决问题
1. 那知道了问题,可以从多个⽅向来解决这个问题,本⼈选择了⼀个⽅向是把⼀个校验开关属性设置为false。
2. 其实最好的⽅法还是遵循规范,URL就不应该带中⽂字符,本⼈是属于后期维护这个项⽬,业务也不清晰,如果修改了url业务
代码影响较⼤,但是也不能把校验全都关了,你查看shiro升级的⽇志发现就是加了⼀个这个全局过滤器和⼀些代码来修复漏
洞。 选择了⼀个⽐较折衷的⽅法,就是把中⽂校验给关了。(这⾥补充⼀下 修改PathInfo()怕对全局影响也⽐较⼤)
即注⼊在spring的 InvalidRequestFilter的blockNonAscii属性设置为false
这时候你也要调试源码。
简单说⼀下我的思路:⼀看到filter肯定是职责链设计模式,先考虑什么地⽅注⼊了这个filter.查看该类的引⽤
然后查看谁⽤了这个枚举
org.apache.shiro.spring.web.ShiroFilterFactoryBean
createFilterChainManager() 在这⾥⽤到
/**
* This implementation:
* <ol>
* <li>Ensures the required {@link #setSecurityManager(org.SecurityManager) securityManager}
* property has been set</li>
shiro安全框架
* <li>{@link #createFilterChainManager() Creates} a {@link FilterChainManager} instance that reflects the
* configured {@link #setFilters(java.util.Map) filters} and
* {@link #setFilterChainDefinitionMap(java.util.Map) filter chain definitions}</li>
* <li>Wraps the FilterChainManager with a suitable
* {@link org.apache.shiro.FilterChainResolver FilterChainResolver} since the Shiro Filter
* implementations do not know of {@code FilterChainManager}s</li>
* <li>Sets both the {@code SecurityManager} and {@code FilterChainResolver} instances on a new Shiro Filter
* instance and returns that filter instance.</li>
* </ol>
*
* @return a new Shiro Filter reflecting any configured filters and filter chain definitions.
* @throws Exception if there is a problem creating the AbstractShiroFilter instance.
*/
protected AbstractShiroFilter createInstance()throws Exception {
log.debug("Creating Shiro Filter instance.");
SecurityManager securityManager =getSecurityManager();
if(securityManager == null){
String msg ="SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if(!(securityManager instanceof WebSecurityManager)){
String msg ="The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager =createFilterChainManager();
//Expose the constructed FilterChainManager by first wrapping it in a
// FilterChainResolver implementation. The AbstractShiroFilter implementations
// do not know about FilterChainManagers - only resolvers:
PathMatchingFilterChainResolver chainResolver =new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
//FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
//injection of the SecurityManager and FilterChainResolver:
return new SpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
发现在这⾥filter都是通过FilterChainManager进⾏管理的,并会进⾏初始化的创建
其实,这时候你还要确认⼀件事,就是项⽬的filter是否是全局唯⼀的,会不会每次都进⾏new,我是通过调试源码进⾏判断的)
我需要在filter初始化后修改这个InvalidRequestFilter的默认属性。
所以我这边的做法是⾃定义了⼀个ShiroFilterFactoryBean
/**
* ⾃定义的 CustomShiroFilterFactoryBean, 使⽤了⾃定义的serveletresponse, 避免重定向到登录页⾯后, url⾥出现JSESSIONID=xxx
*
* @see ShiroFilterFactoryBean ShiroFilterFactoryBean
*
* @author <a href="mailto:ningyaobai@gzkit">bernix</a>
*        ⼗⼀⽉ 18, 2016
* @version 1.0
*/
public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {
private static final Logger logger = Logger(CustomShiroFilterFactoryBean.class);
@Override
public Class getObjectType(){
return CustomSpringShiroFilter.class;
}
@Override
protected AbstractShiroFilter createInstance()throws Exception {
logger.debug("Creating Shiro Filter instance.");
SecurityManager securityManager =getSecurityManager();
if(securityManager == null){
String msg ="SecurityManager property must be set.";
throw new BeanInitializationException(msg);
}
if(!(securityManager instanceof WebSecurityManager)){
String msg ="The security manager does not implement the WebSecurityManager interface.";
throw new BeanInitializationException(msg);
}
FilterChainManager manager =createFilterChainManager();
//Expose the constructed FilterChainManager by first wrapping it in a
// FilterChainResolver implementation. The AbstractShiroFilter implementations
// do not know about FilterChainManagers - only resolvers:
PathMatchingFilterChainResolver chainResolver =new PathMatchingFilterChainResolver();
chainResolver.setFilterChainManager(manager);
// URL携带中⽂400,servletPath中⽂校验bug
Map<String, Filter> filterMap = Filters();
Filter invalidRequestFilter = (DefaultFilter.invalidRequest.name());
if(invalidRequestFilter instanceof InvalidRequestFilter){
((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);
}
//Now create a concrete ShiroFilter instance and apply the acquired SecurityManager and built
//FilterChainResolver.  It doesn't matter that the instance is an anonymous inner class
//here - we're just using it because it is a concrete AbstractShiroFilter instance that accepts
//injection of the SecurityManager and FilterChainResolver:
return new CustomSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
}
}
码哥zhkkjun 给出了另⼀个修改的⽅案 具体可以⾃⼰测试⼀下是否有问题public class CustomShiroFilterFactoryBean extends ShiroFilterFactoryBean {
@Override
protected FilterChainManager createFilterChainManager(){
FilterChainManager manager =ateFilterChainManager();
// URL携带中⽂400,servletPath中⽂校验bug
Map<String, Filter> filterMap = Filters();
Filter invalidRequestFilter = (DefaultFilter.invalidRequest.name());
if(invalidRequestFilter instanceof InvalidRequestFilter){
((InvalidRequestFilter) invalidRequestFilter).setBlockNonAscii(false);
}
return manager;
}
}
问题完美解决

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。