新版正方教务系统登录实现
最近开学后相信很多同学都发现课表小程序等无法使用了,这是因为学校更新了正方教务系统,导致了大批基于旧版正方系统的校园小程序无法继续爬取课表。
之前曾在GitHub上看到过本校师兄开发的school-api–一个基于旧版正方的python SDK,但新版无法使用。因此花了两天时间研究了下新版正方的登录(能登录后续的就EZ啦~) 
既然都弄了,因此计划开发一个新的SDK。我比较懒 暂命名为new-school-sdk,项目目前还在开发中,先将登录的流程、验证码识别的思路罗列出来。(拿到了cookies 还有啥不能干嘛)
项目Github地址: https://github.com/Farmer-chong/new-school-sdk
登录前期准备
 
通过观察发现,有以下几个难点:
- 新版正方使用Java进行开发且并非前后端分离,因此只要我们能拿到cookie即能完成登录。
- 验证码的识别
- 正方使用了Rsa对数据进行加密
针对上述问题,开始一一解决
验证码部分
前置工作准备好后,开始从服务器获取验证码并进行验证
获取验证码
网络抓包发现,验证码是异步获取的,每次刷新都会发送一个请求到/zfcaptchaLogin
 
请求报文内容有:
| 1 | "type": "refresh" | 
响应报文内容:
| 1 | imtk: "29730cb5-d7ff-4fc9-aa9d-e3efc0a07f55" | 
观察请求报文发现需要type、rtk、time和instanceId这几个字段。
其中rtk未知,因此开始寻找其出现的地方。通过查找发现rtk出现在一个js文件中,初步猜测rtk是一个令牌,由服务器随机生成的。
因此我们要先获取rtk令牌,然后利用正则表达式将其值提取出来。
 
下载验证图片
但现在仍然无法获取验证图片的原始数据,再观察img的src属性,得知响应报文中的mi和si分别别是验证码和滑块。并且需要的url参数我们也已经获取了。
向/zfcaptchaLogin发送一个GET请求,请求参数如下:
| 1 | type: image | 
滑动验证码识别
上文中有提到,参考这篇文章: https://blog.dairoot.cn/2021/06/26/zf-sliding-captcha/
大致流程如下:
- 将图片灰度化
- 识别出一段颜色差小于阈值的线(竖的)
- 识别出来的这段线不能太短(要和缺口差不多高)
因此即可计算出该线的x轴坐标,因此得到滑块偏移量。
模拟人手拖动&发起验证请求
从上一步中,我们得到了偏移量X和Y,接下来就要开始模拟人手拖动滑块的过程了。人手滑动验证码时,一般都是先快后慢的一个速度曲线,因此利用物理学公式分段设置加速度a,前半段a > 0,后半段a < 0。
当前速度用v表示,初速度用v0,位移用x,时间用t,它们之间满足如下关系:x = v0 * t + 0.5 * a * t^2v = v0 + a * t
移动算法的代码实现如下:
| 1 | def _get_track(self, distance, y): | 
至此,我们得到了发起请求的所有数据,因此向/zfcaptchaLogin发送一个POST请求,请求体如下:
| 1 | type: verify | 
当验证通过时,得到如下的响应体:
| 1 | msg: "" | 
登录部分
获取RSA公钥
通过查看页面源码和点击登录后抓包,登录发送一个请求到/xtgl/login_slogin.html,然后返回一个302的跳转。
其中请求报文内容如下:
| 1 | csrftoken: csrftoken | 
此处csrftoken和mm两个字段是未知的。其中csrf令牌是为了防止攻击的,一般包含在form表单中,由后端生成。因此我们可以直接从页面中提取。如下图:
 
而mm字段,通过对前端异步请求部分的代码进行分析后,发现是利用RSA进行加密,从抓包中可以发现一个发送到/login_getPublicKey.html地址的GET请求。其响应体内容如下:
| 1 | exponent: "AQAB" | 
因此得到了RSA的指数和模,但这里的modulus长度为 172。大概率是正方修改过加密,在JavaScript文件的注释中也可以看到。
本来是打算自己重写一个python版的实现,后来在GitHub上发现已有前人栽树,我乘凉就好啦! 
到现在为止,整个登录流程的未知项就全解决了!🛫🍯
开始登录
再次观察数据包的流程,得知登录各项的顺序并做优化:
! 注意,在登录发生302跳转的时候,cookie会发生改变 !
- 访问登录页面,获取csrf和原始的cookies
- 获取rsa公钥
- 处理滑块验证
- 发起登录,得到登录后的cookie
成功截图:
 
后记
sdk开发中,希望大佬们多多给意见或者一起开发哈!