前面代码逻辑还是差不多的,先从context中获取principal对象,然后检查是是否为空,如果为空则调用getRememberedIdentity创建然后设置到context中,否则直接返回,所以如果要触发反序列化这里必须要为空 。我们跟进resolvePrincipals方法中看一下 。
public PrincipalCollection resolvePrincipals() {PrincipalCollection principals = getPrincipals();if (CollectionUtils.isEmpty(principals)) {AuthenticationInfo info = getAuthenticationInfo();if (info != null) {principals = info.getPrincipals();}}if (CollectionUtils.isEmpty(principals)) {Subject subject = getSubject();if (subject != null) {principals = subject.getPrincipals();}}if (CollectionUtils.isEmpty(principals)) {Session session = resolveSession();if (session != null) {principals = (PrincipalCollection) session.getAttribute(PRINCIPALS_SESSION_KEY);}}return principals;}这个方法就和前面的resolveSession有点不太一样了,他第一次调用了getPrincipals如果为空还从其地方也获取了相关对象来构建principals,可以看到最后也获取了session对象 。如果前面已经设置了session对象,那么这里返回的就一定不会是null,最后就不会调用rememberMe导致反序列化 。所以我们在利用shiro反序列化时一定要删除cookie中的JSESSIONID字段 。
最后使用context创建对应环境的subject对象,这个对象是shiro框架对开发者使用的一个接口对象,在登录及认证授权时都是调用的该对象,由他内部再去调用securitymanager对象的操作 。
最后回到AbstractShiroFilter#doFilterInternal中,调用了Subject#execute(java.util.concurrent.Callable)方法,传入了updateSessionLastAccessTime和executeChain方法 。这里如果直接跟进这两个方法回错过一个细节,就是将subject对象设置打ThreadLocal中,但由于这个和shiro中的漏洞关系不大就不再跟进分析了 。
updateSessionLastAccessTime方法没什么用就不说了,下面跟进executeChain说一下shiro中的路径匹配 。

文章插图
image
在这个方法里面就分两步,第一步根据request获取对应的过滤器,然后第二部执行过滤方法 。
protected FilterChain getExecutionChain(ServletRequest request, ServletResponse response, FilterChain origChain) {FilterChain chain = origChain;FilterChainResolver resolver = getFilterChainResolver();if (resolver == null) {...return origChain;}FilterChain resolved = resolver.getChain(request, response, origChain);...return chain;}public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {FilterChainManager filterChainManager = getFilterChainManager();if (!filterChainManager.hasChains()) {return null;}String requestURI = getPathWithinApplication(request);for (String pathPattern : filterChainManager.getChainNames()) {if (pathMatches(pathPattern, requestURI)) {return filterChainManager.proxy(originalChain, pathPattern);}}return null;}首先获取FilterChainResolver对象,这个对象就是在WebEnvironment创建时初始化的,然后在ShiroFilter初始化时设置到该类的属性中 。然后根据请求URL匹配对应的过滤器,最后创建一个filterChain的静态代理类 。其中shiro权限绕过的原因主要就是由于路径匹配时匹配到了错误的过滤器或未匹配到shiro内置的过滤器,导致绕过shiro的过滤器检查,但其请求URL被tomcat过滤器处理后仍然能获取对应的资源 。SHIRO-550源码分析上面分析了shiro框架的大概流程,在介绍DefaultSecurityManager#createSubject(SubjectContext)中创建Principal时就会对cookie中的rememberMe解析并反序列化 。下面就从这开始进行深入分析 。
首先进入org.apache.shiro.mgt.DefaultSecurityManager#getRememberedIdentity方法 。
protected PrincipalCollection getRememberedIdentity(SubjectContext subjectContext) {RememberMeManager rmm = getRememberMeManager();if (rmm != null) {try {return rmm.getRememberedPrincipals(subjectContext);} catch (Exception e) {......}}return null;}public PrincipalCollection getRememberedPrincipals(SubjectContext subjectContext) {PrincipalCollection principals = null;try {byte[] bytes = getRememberedSerializedIdentity(subjectContext);if (bytes != null && bytes.length > 0) {principals = convertBytesToPrincipals(bytes, subjectContext);}} catch (RuntimeException re) {principals = onRememberedPrincipalFailure(re, subjectContext);}return principals;}其中getRememberedSerializedIdentity方法主要是获取rememberMe的值并进行base64解密,然后convertBytesToPrincipals对base64解密后的值进行AES解密并反序列化 。注意这里的异常捕获,先提一下后面再回来分析 。我们继续跟进convertBytesToPrincipals方法 。
文章插图
推荐阅读
- “鲶鱼须”取代“高马尾”,中学女生发型大变样,越来越难理解了
- 安娜李的性解放,一部深入探讨自我价值和性观念的电影
- 解读机关公务员视同缴费年限规定,你真理解了吗?
- 手机丢了怎么能找回来oq
- 胡总发声,“牵手门”事件大结局,网友称:无法理解胡夫人的大度
- |张雪峰回应文科歧视,其实是家长们理解错了,忠言逆耳利于行
- 麦家琪|麦家琪儿子怒斥母亲当年行径,艳星总是被人不理解
- 现货黄金哪里可以开户卖
- 孙俪|“蔡公馆”蔡康永,怎能理解孙俪,4次家庭危机,均不是无常?
- |不带钩调漂的好处,如果是初学者,能对调漂有更深的理解
