共计 3881 个字符,预计需要花费 10 分钟才能阅读完成。
首次分析
首先按照正常流程进行,抓包查看登录提交的数据。
Header 如下
POST http://jwgl.ayit.edu.cn/cas/logon.action HTTP/1.1
Host: jwgl.ayit.edu.cn
Connection: keep-alive
Content-Length: 1124
Accept: text/plain, */*; q=0.01
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.97 Safari/537.36
Content-Type: application/x-www-form-urlencoded
Origin: http://jwgl.ayit.edu.cn
Referer: http://jwgl.ayit.edu.cn/cas/login.action
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cookie: JSESSIONID=3A9F6F4B8DD59938CB4E13F79E944D3C
提交的数据内容如下
params=QzMyMDQwRTc1QjA1MDRBRjk5QTgyRUZEMDlBQjVGMTZEODlDMEIyQ0E5MkRFRDAzMDJGRjY2QjhFREMzMkZENDMzQUFEQzMzODE2NzJENjA3MDMyRjAyRkY1QTk1OEQwMTc1NzQ2OTExQTdDODdDNjdFREU5NTlCNEU5Q0NBNjAzRTY0MTQ4REIzQkM0QTY2NEFGRkI4QjRFNDg4MkQzMUYxMzBDMkEwMEM3MDA3MjU5NUEwMjUwQkFBNjQ2QjVEOUQ5RUY2QTA4MkNCQ0ZDQjdDMkQ4OTE5NDEzREM2NjE3MkM2M0ExNTFFQUY0QzMzRjZCOEQ4QjQwRkZCQTY4M0M1NzZCNzY0Q0I5Q0VFMzQ2QjQ4N0U5MjRFM0VCODcyMTVGQ0U4RTI5OUNBOTdCRDMyRUUzQTIxNzY4MEY4ODRFNzI0Q0FGODk2MTRFREE2OTM5RkJFRUNBODAxRTYyNzgwNkU5RUM2MEFDRjMxNDVFMDI1RjI4QTI3MTY2RjU0ODE2RDc2MkNDMzEzMDM3MjgxQTlDRDA4QTA5NjhDQzM4NDJGOEEzMTA1Njc0MzI5ODRFM0I5MTREMjQ3NkZEOTlEMzE4NjEwMTg4MjJGNTU0REMwMDYyQ0NEMDI3QkQ3NDdFNjM0QTA4NjQ1OTU4NjE2OEU0RENDMEE3NzRGOEFDNkY0OUVGM0ZERDM4RjgyNThBRUUwOEMxRjhDMDlCMzI2RERFNTI2N0FGNDk2NTBCQ0I5MkNFMzdBQTk4RUE3NDU0QTY5NjhENTRDMjJGRjgyRDJGRjNDRDY0NjkxMzM5NkU3QjI5ODhFRkMwRDdGRTJCNUU4RjYwQzQxMkMxRUZCOUU0MEU3Q0ZDQzIxNjAwNEZGNTJBQzZGMUMzRTk0QzIwQTgwNUU3MDMwRDAzNjNGN0U1QjIyNTA2REEzM0ZFMzg0ODQyMkU2M0MyOUJFNjhBMjY0OUFFRENENThBNkRGMUYzNEYzQzU5NUE2MEY2REM2QkM2RDNGRThERTQwOTJFMDI0QzQxQkY4MTcwRA==&token=a5ac4f2525e4860adb84cefc967368e8×tamp=2020-07-06 23:52:37
共提交了 3 个参数,分别是加密后的 params,token 和明文字符串 timestamp
返回值如下
{"message":"验证码有误!","result":null,"status":"401"}
由于前端的特性,所有的加密肯定是在 JS 内实现,所以接下来我来逐条进行分析。
token 分析
因为 params 是个加密字段,解密需要一定时间,timastamp 是明文不用管,我就先从 token 入手。
查看 html 结构,这是登录按钮
可见点击按钮后执行 doLogon()方法,通过在可能的 JS 里搜索方法名,最终发现该方法出现在 LoginExt.js 中,如下图
通过查看函数结构,很容易可发现 token 的位置
var token = j$("#yhmm").val();
可见 token 的值就是用户密码的值,但这显然是错误的因为我们抓包显示 token 是一个类似于加密后的值
下断调试后发现,在调用 getEncParams 这个方法后 token 就变成加密后的值了,同时这个方法也是生成整个登录表单的核心方法!至此感觉分析预计会很快结束。
getEncParams 方法分析
既然找到了核心方法,那只需要看看这个方法里都是什么就好了,通过 F11 单步进入方法,发现我进入了一个新的文件里。
而很巧的是,这个 SetKingoEncypt.jsp 在刷新首页时会加载
接下来就非常好办了,通过查看方法可知,token 是将之前组装好的 params 和现在的时间(注意是时间而不是时间戳)都进行 md5 加密后再进行 md5 加密,所以为什么我首次分析时觉得 token 就是个 md5 加密后的值。
总结
至此,整个登录流程就已经分析完毕。整个登录流程可以总结为:
- 获取输入的用户名,密码,token(和密码相同),验证码(id 为 randnumber 的元素值)
- 校验用户名和密码是否合法① –> kutil.isPasswordPolicy()方法
- 获取 txt_mm_expression、txt_mm_length、txt_mm_userzh 的值 ②
- 初次加密 password
- 拼接 p_username 和 p_password
- 对用户名进行编码 ③
- 拼接 params ④
- 对 params 进行加密 –> getEncParams()方法
- 封装完毕,发包登录
可见登录流程是多么复杂,但复杂之余并不困难,按照流程走就可以。
对于青果的加密函数(SetKingoEncypt.jsp),在实际使用时其实无需重写,只需要加载和调用即可。当然若语言不通则可能需要重写加密函数。
关于这个加密函数如何自己写一份,我会在下一篇文章内说明。
到这里对登录功能的分析就结束了。
附录
①用户名和密码校验方法函数
/**
* 检测密码是否符合密码策略
* 1、用户密码不能与登陆帐号一致。* 2、用户密码必须为 6 位或 6 位以上字符长度,并且包含有字符和数字。* return 1- 符合; 0- 不符合
*/
my.isPasswordPolicy = function(username, password){if (password == "" || password == null || username == password){return "0" ;}
var passwordlen = new String(password).length ;
if (passwordlen < 6){return "0" ;}
/* 2019.2.16 因密码复杂度要求可以设置不需要包括字母和数字而去掉
var letter = new String(password).replace(/[^A-Za-z]/g, ""); // 保留字母
var letterlen = letter.length ;
if (letterlen == passwordlen) {return "0";}
var digit = new String(password).replace(/[^0-9]/g, ""); // 保留数字
var digitlen = digit.length ;
if (digitlen == passwordlen) {return "0";}
*/
return "1" ;
}
③在编码用户名时用到了一个 SessionID,其出处是
这个值是直接服务端渲染直接写死在网页内,所以可以直接调用_sessionid 来获取
④params 拼接方法以及拼接后的值示例
拼接方法:
var params = p_username+"="+username+"&"+p_password+"="+password+"&randnumber="+randnumber+"&isPasswordPolicy="+passwordPolicy+
"&txt_mm_expression="+txt_mm_expression+"&txt_mm_length="+txt_mm_length+"&txt_mm_userzh="+txt_mm_userzh;
示例值:
"_u1234=dGVzdDs7M0E5RjZGNEI4REQ1OTkzOENCNEUxM0Y3OUU5NDREM0M=&_p1234=5ec82405514679333a2c7ab58dd2b980&randnumber=1234&isPasswordPolicy=0&txt_mm_expression=4&txt_mm_length=4&txt_mm_userzh=1"