首次分析
首先按照正常流程进行,抓包查看登录提交的数据。
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"
发表回复