Shiro550流程简析

Uncategorized
1.5k words

流程调试之加密

根据网上的复现文章,我们知道在登录的时候会先调用DeafultSecurityManager这个类里面的login方法,这里直接来到这个目标类里,给Login方法加上一个断点。

流程解释
这里是在这个info这里先停了一下,根据我们传入的token对象,实例化一个名为info的AuthenticationInfo对象(token的属性包括当前输入的账号和密码,host路径和remeberme选项),这里的try和catch语句相当于一个判断是否登录成功的if语句
相关解释如下(来自new bing):
( AuthenticationException 是一个 Java 异常类,当访问命名或目录服务时发生身份验证错误时抛出此异常。例如,当用户程序提供的凭据无效或以其他方式无法将用户验证到命名/目录服务时,可能会发生身份验证错误 )
这里我们是登录成功了,直接跳到如下部分

根据本类定义的createSubject方法生成了一个名为loggedIn的对象
这里因为login这个方法最终的返回值就是我们的loggedIn对象,我们给loggedIn这里打上一个断点,持续跟踪它,这里先跟进一下createSubject这个方法的定义

相当麻烦,又出来了很多新的量,先继续跟进一下creatSubjectContext()这个方法,代码部分相当简单,就只是return了一个DefaultSubjectContext的无参构造,这里直接贴一下DefaultSubjectContext的属性定义部分,没发现和我们Cookie直接相关的属性,步出回到createSubject这里


来到实际调用的createSubject重载方法这里
后面对这些涉及的方法都跟进了一下,没发现和cookie生成有关的部分,步出回到第二步。

跟进onSuccessfulLogin方法

跟进rememberMeSuccessfulLogin方法

跟进第一行的getRemberMeManager()

这里是直接返回了一个名为remeberMeManager对象,其属性大致如下
可以看到,相关加密的模式,秘钥都在此设定
其余的属性如cookie的设定也在此有迹可循
估计后面的cookie加密就是对此对象操作,给此对象加个断点,重点关注

继续步出回到remeberMeSuccessLogin这里
步入onSuccessfullLogin方法(经过调试,这个方法就是remeberMesuccessfullLogin执行的最后一步1)

emmm,,别忘了,这里的subject就是我们一开始传入的loggedin,这里第一行代码调用了一下,还是要跟进以下的(仔细看了一下,这个subject的属性里面也嵌套着一个remeberMeManager)。

直接步入最终实际调用的重载结果

这里跟进一下着两个部分
(总结分析一下,就是对rememberMe这个cookie字段进行一些基本的设置,并不涉及加密过程,重新步出分析,默认把rememberMe这个字段的初始值设置为deleteme)


这里会先进行一个remeberMe选项是否勾上了的判断
(这个值在token里,勾上了则进行下面的部分,对rememberMe字段的值进行修改)
这里是运行到了remeberIdentity这里,继续跟进

出来的定义如下,不知道这里的principals对象是干什么的,但这显然不是终点,继续跟进真实调用的rememberIdentity方法

出来了这么个具体方法
这里的第一个方法调用了我们刚才定义的principals对象,读方法名感觉应该是和序列化有关的一个方法
,再度跟进

得到如下定义
第一行很简单,对principals对象进行序列化处理,再把结果存入bytes数组中(从这里大体可以猜测出来,principals对象应该是通过我们传入的用户名和密码实例化出的对象)
第二行就是检测当前是否存在相应的加密方法,跟进审计了一下,能够发现当前的加密方式为AES加密,存在加密方法,可以进行加密。
跟进审计encrypt方法。

最后几步了,详细一点,encrypt这个方法本质上还是套用的cipherService.encrypt这个方法(感觉可以直接在刚才的类里调用这个….),其实这里一看就知道是对序列化对象进行aes加密,就不跟进了,分析这种加密源码还是挺有难度的,我们直接步出。

回到rememberIdentity , 最后一步了 , 调用rememberSerializedIdentity方法,我们跟进一下

rememberSerializedIdentity部分代码如下
这里只筛选了关键部分,前面的常规传值没贴出来
可以看到rememberSerializedIdentity方法对我们aes加密后的序列化数据又进行了一次base64编码,并且把这个值设给了cookie(看了一下,这里的cookie对象就是我们的rememberMe)

至此,rememberMe的cookie生成完毕


流程调试之解密

这里我们不知道到底是在哪里进行的解密流程,但我们在AbstractRememberMeManager这个类里面找到了一个名为decrypt的方法(和encrypt方法在同一个类下)

查看调用帧,查看调用的层次结构关系


我们最终选择追溯到resolvePrincipals这里便停止追溯。
(根据上面加密部分的调试,我们知道这里Principals与cookie关系紧密)
大体看一眼然后跟进getRememberedIdentity方法。

跟进getRememberMeManager方法

返回结果如下:

步出,跟进getRememberPrincipals方法

来到这个地方跟进一下getRememberSerializedIdentity方法。


直接看关键部分
String base64 = getCookie().readValue(request, response);
把cookie值取出来,进行base64解密,返回一个decoded

得到了bytes数组后,我们继续跟进一下这个部分,一看就是跟反序列化有关的

大象真白了(雾)
我们最后再进到这个反序列化方法看一看


大体如下,很普通的反序列化实现
至此,Shiro 550流程分析完成