这样暴露 Token 属于是你瓜特色程序了,疫情没事干就水一贴罢。
0x00 前言
然而毕竟是一年以后的更新,因此还是容我赘述一下这个软件本应有的 「前言」:
在新冠疫情的背景之下,想必很多学校都要求学生每日申报自己的健康状况。但是日子一天天过去总有忘记的时候——轻则全班公开处刑,重则全院公开处刑,尴尬至极。后来接入了企业微信,如果不填每天中午 11:30 又准时来催你填……每天还得去对着表格整几下,实在有些麻烦,遂考虑制作一个自动化填报的程序来减轻自己的工作量。
警告 / 请认真阅读本部分
- 本软件设计之本意为技术学习,请在遵循法律及学校各项规定的前提下使用本软件。
- 如您需要使用该软件,请确保您的身体状况良好,如实申报自身身体状况。
- 若您的身体状况出现异常,应立即停止使用本软件、关闭云函数自动触发功能,并及时于学校系统更改每日申报情况。
- 因使用该软件误报身体状况而引发的不良后果应由您自行承担。
- 本软件原理是提取上一次的填报结果来提交,如果您的所在地发生改变,请自行手动填报一次,理论上程序会自动跟进后续的填报并与之同步。如出现异常烦请反馈!
- 该软件并非万能,请时常检查填报结果!
本项目 Github 仓库:
如果 Github 访问异常,请浏览 Gitee 镜像。
0x01 2021 年 12 月疫情填报系统的两处修改
那就直入主题。2021 年 12 月,疫情突然袭击西安,校内连续高频率的核酸检测成为了日常。基于此因,校方对疫情填报系统做出了两处改动:
- 加入了新问题「近 48 小时内是否进行过核酸检测」。
- 在对
/wx/ry/ry_util.jsp
POST 每日健康状况表单时,加入了签名校验;
第一个问题非常好解决,只需要在 POST 的时候加入一对键值 'hsjc': '1'
。
第二个问题我一开始看到也愣了——加密校验?那不是脚本通杀了?让人意外的是,签名参数 sign
和 timeStamp
竟然暴露在 /wx/ry/jrsb.jsp
的 js 中,一览无余。那么获得一个合法的签名也就变得容易许多,只需要用已获取的参数来伪造请求即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| def init_info(self): self.session.post(url_jrsb) header_for_init = {...} data_for_init = {...} res_jrsb = self.session.post(url_jrsb, data=data_for_init, headers=header_for_init) self.timeStamp = re.findall(re.compile('(?<=&timeStamp=).*(?=\')'), res_jrsb.text)[0] self.sign = re.findall(re.compile('(?<=sign=).*(?=&)'), res_jrsb.text)[0] (...)
def submit(self): self.session.get(url_jrsb) header_for_submit = {...} self.data_for_submit = { '......', 'hsjc': '1', } url_ry_util_with_token = url_ry_util + '?sign=' + self.sign + '&timeStamp=' + self.timeStamp self.session.post(url=url_ry_util_with_token, data=self.data_for_submit, headers=header_for_submit)
|
这样的话也就解决了上述的两处变化。
0x02 其他一些改进
2.1 判断填报成功的逻辑
以前只是通过填报后跳转页面的提示来判断填报是否成功,这样一来并不是对填报数据的直接判断,二来也不好判断今天到底填没填过,会造成当天重复填报,并不优雅。
因此引入如下判断:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
if not (self.judge_last_report_is_today(self.get_last_report_time(data_for_init, header_for_init))): url_ry_util_with_token = url_ry_util + '?sign=' + self.sign + '&timeStamp=' + self.timeStamp self.session.post(url=url_ry_util_with_token, data=self.data_for_submit, headers=header_for_submit) else: print('今日已填报,无需重复填报!') return
if (self.judge_last_report_is_today(self.get_last_report_time(data_for_init, header_for_init))): print('申报成功!') if user_config.SC_switcher == 1: Pusher.scPush(self) else: print('申报失败,请重试!') if user_config.SC_switcher == 1: Pusher.sc_push_when_wrong_info(self)
def judge_last_report_is_today(self, report_time): report_time = self.string_toDatetime(report_time) if report_time.date() == datetime.today().date(): return True else: return False
def get_last_report_time(self, data, header): last_report_time = \ etree.HTML(self.get_last_report(data, header)).xpath( '/html/body/div[1]/div[2]/div/div[2]/div[1]/div[2]/text()')[0] return last_report_time
|
2.2 获取上一次核酸检测的状态
其实和上面大同小异,水个贴记录一下更新就得了。
1 2 3 4 5 6 7 8 9 10 11 12
| self.hsjc = self.get_last_hsjc_status(data_for_init, header_for_init)
def get_last_hsjc_status(self, data, header): nuc_acid_test_status = \ etree.HTML(self.get_last_report(data, header)).xpath( '/html/body/div[1]/div[2]/div/div[2]/div[2]/div[2]/text()')[0] if nuc_acid_test_status == '已检测': return '1' else: return '0'
|
至于其他原本的细节,还是回到第一篇去看吧~那里写得还是更加详细一些。