本文转载自看雪论坛【作者】rdsnow
不得不说,最近的 Python 蛮火的,我也稍稍了解了下,并试着用 Python 爬取网站上的数据
不过有些数据是要登陆后才能获取的,我们每年都要到某教师教育网学习一些公需科目,就拿这个网站试试,关键是对网站的分析
打开浏览器,输入网站网址 http://www.jste.net.cn ,按F12调出浏览器的开发者工具,选中 Network ,并勾选 Preserve log,防止切换网页时信息丢失
网页上输入账号,密码输入“123456”,验证码输入“abcde”,验证码不要输正确的,否则密码错5次,会被网站锁定账号30个小时,验证码倒是可以随便错
登陆后(当然登陆不上,会跳转到另一个登陆页面),在开发者工具中看到与服务器的数据交换
第一个是get验证码图片的,第二个就是向网站提交数据的,点一下第二个信息
这是个 Post 请求,重点看红框中的提交数据,randomCode就是输入的验证码了,x,y应该是点击的按钮控件的位置了,有cookie后就没有提交这个数据了,可以忽视,returnURL、appId,encrypt每次都是一样的,也不用管他,重点是 reqId 和 req 这两个 key 的值了,reqId猜想是点击按钮时取到的时间戳,可以复制这个数据到验证下 Unix时间戳(Unix timestamp)转换工具 单位选毫秒,确实是刚刚提交数据的时间,就剩下一个数据了,这个key的数值很长,下面来寻找这个数据是从哪里的来的
可以看到 login.jsp 下可以看到 encode.js、string.js、des.js 从名字上就能看出这几个是用来加密提交数据的,右键 login.jsp,选择 “Open in Sources panel”
可以跳转到 “源” 选项卡,看到 ’login.jsp‘ 的源码,如果格式混乱,比如所有代码在一行中,不便于观看,可以点击界面下方
的中括号,开发者工具会自动给你重新格式化代码。
仔细分析 login.jsp 的代码,看到
|
|
找到这段代码,其中主要是对输入检查的部分,重点看这两处
|
|
此处对密码进行第一次加密
|
|
第一行:将用户名进行 URL 的格式编码
第二行,取时间戳赋值给 reqId
第三行传入用户名,加密后的密码和验证码进行验证,函数返回值赋给变量 str,正是提交数据的 req 的值
在两个加密函数入口设置断点,开发者工具设置断点的,只要在这个代码的行号上点击鼠标就行了,设好断点后,再次输入用户名密码和验证码,重新提交,程序被断下:
F11单步进入第一个断点,这里需要点击界面下面的中括号重新格式化下代码,单步跟进后看到:
|
|
这个函数返回的 f 就是密码第一次加密后的结果了,这个代码是用什么工具变成这样的不太清楚,如果出现 _$_7151[n] 这样的字符可以查询代码最上面的列表
代换,大致过程不详说,跟一遍就知道了,就是循环从密码中取三个字符 g、h、j,然后将三个字符的ascii码左移或右移,或和其他结果加加减减,得到的结果 k、l、m、o 查询表格替换字符,如果密码长度不是 3 的整数倍,则查表结果用 “=” 替换,将循环得到的查表结果依次连接,并反序,得到一个密码加密后的密码
至少将密码进行两次这样的加密计算,如果用户名的长度是奇数,再进行一次加密,加密的过程只需要复制代码到 python 中,修改成 python 的格式就可以了。
步过了对密码的第一次加密后,继续步进上面设下的第二个断点
|
|
这是一段循环进行 DES 加密的代码,先将data, firstkey, secondkey进行字符间插入一个字节的0, 然后不是 64 位整数倍长度的从上面代码看,相当于在后面补上 0 了
从data中取出一段64位数据,循环用 firstkey 和 second 中的 64 位做密钥,层层加密,得到的结果和 data 中其他 64 位加密的结果串联后就是 req 的值了
因为 key 都是 64 位的,再加上本身 sources 中也看到了 DES.js 文件,所以 enc(tempBt,secondkeyBt)应该就是 DES 算法了。
但是自己写代码模拟登陆确发现结果和自己跟的结果不同,从代码中看,DES 采用了 ECB 模式,不是 CBC 模式,PAD_mode 也没问题,都64位,不需要 DES 自己填充啊。没办法,只得硬着头皮继续跟进 DES 加密的代码
我们知道,DES 加密需要先对 key 进行 置换,得到 56 位密钥,标准的 DES 都有个置换表,正常的 DES 置换表是这样的
|
|
即将 key 的第 56 位放到第 0 位,第 48 位放到第 1 位…………最后置换出 56 位的 key,再分成 2 个28 密钥,循环左移和右移,然后 对 IP 置换后的 data 加密,进行 Sbox 盒替换 和 Pbox 替换,再进行一次 IP-1 置换得到密文,解密算法一样。
但跟进 DES 加密函数没多久就发现问题了,找到密钥置换的函数
|
|
并跟进:
|
|
这里修改了标准的置换表,用了一个嵌套循环生成 56 位密钥,即把
原来 key 的 56 位 –> 第 0 位,48 位 –> 第 1 位,40 位 –> 第 2 位,…………0 位–> 第 7 位
原来 key 的 57 位 –> 第 8 位,49 位 –> 第 9 位,41 位 –> 第 10 位,………… 1 位 –>第 15 位
…………
最后丢弃原 key 的第 63,55,47,39,31,23,15,7 位(位置号从 0 开始)
在 python 中不能直接使用标准的 DES库了,可以把标准库中的 pyDes.py 文件拷贝到工程同目录下,改名为 Des,py,并导入工程
from Des import *
另外在 Des.py 中找到 key 的置换表,修改成
|
|
就可以正常使用 Des 了
最后附上 python 代码:
效果
最后思考了下,很多网站的数据都是明码提交的,或者是简单的加密提交的,这个网站在加密上花了一些工夫
但是js脚本最大的问题就是别人可以看到源码,虽然网站登陆成功后立即删除了js文件,但是只要出现了就会被发现,我网上搜索了下隐藏源码的办法,但是水平才菜了,没学过 java ,也没看懂。
最后补充下:DES加密的数据 data 是用户名的” URL格式 + 换行 + 密码第一次加密得到的文本“
firstkey 是提交时得到的时间戳,secondkey 就是输入的验证码