继前两次对数据爬取过程中对 js 的分析,这次我们针对网页登录学习一下有关 js 的应用,选择百度登录来分析提交表单中的各个参数。研究学习时间比较长,为了能够讲解清楚,分为两篇来写。
一、前言
工具的使用:之前分析 js 加密,主要是使用 Chrome 的开发者工具,当时网页分析过程中觉得很 OK,直到学习百度模拟登录时,发现仅靠 Chrome 开发者工具无法有效分析 js 代码。因此本篇将配合使用开发者工具以及抓包工具 Charles,这也是我学习过程中的小发现。
关于 Charles 的安装,网上有很多教程,网上关于 Charles 的使用教程大部分是关于手机上如何抓取 https 协议包,而关于windows 系统下抓取浏览器访问 Web 应用的 https 协议包的配置和操作比较少。大家如果安装了 Charles,想要进行 PC 端浏览器 https 协议包的分析,可以参考该篇博文进行配置。
二、网页分析
首先打开 Chrome,访问百度,点击登录按钮。
输入账号和密码,点击登录。根据以往的分析经验,我们在开发者工具 Network 栏查看 XHR 和 Doc,找到模拟登录 POST 的链接。
我们想要模拟登录成功,目标主要有两个:一是构建 POST 请求所需的 Headers;二是构建 Form Data。
1.构建 Headers
仔细查看 Requests Headers信息,和登录页面的 GET 请求对比发现除了 Cookie 不同之外,并没有别的什么特殊要求,所以我们按照最基本的要求来构建 Headers。
2.构建 Form Data
退出帐号,清除缓存后,再次登录,观察 POST 请求的 Form Data 数据,与上一次的记录进行比较,对比标记哪些是变化的。通过多次对比,最后发现:
staticpage: https://www.baidu.com/cache/user/html/v3Jump.html
charset: UTF-8
token: 9b76cbbb4933c882de7eb5d1b5da5ae3
tpl: mn
subpro:
apiver: v3
tt: 1560484918581
codestring:
safeflg: 0
u: https://www.baidu.com/
isPhone: false
detect: 1
gid: F64E6A3-034C-4426-9C2D-13D89A818D93
quick_user: 0
logintype: dialogLogin
logLoginType: pc_loginDialog
idc:
loginmerge: true
splogin: rate
username: xxxx
password: xxxxx
mem_pass: on
rsakey: TGiEkUFvpA2i19N9BLfKZrp6Qza2BSp7
crypttype: 12
ppui_logintime: 9116
countrycode:
fp_uid:
fp_info:
loginversion: v4
ds: xxx
tk: xxxx
dv:xxxx
traceid: ECC85E01
callback: parent.bd__pcbs__qyj5vw
其中红色标记的为变化的,这一部分也是我们将要分析的,先简单看一下变化字段有什么含义。
那我们就从上往下分析,tt 时间戳最简单,就不做考虑。
token 参数
按照以往的习惯,先是利用开发者工具进行搜索,在一番查询后都没有找到有效信息,最后试着利用 Charles 抓包进行搜索关键字段,终于找到了 token 所在位置。(等到百度模拟登录案例结束之后,进行总结才发现该案例不同于以往的分析,不是从 XHR 中或者 Doc 中找到相关内容,很多参数都是在 js 中发现的,但是开发者工具搜索并不能精确定位,也浪费了不少时间。)
在 https://passport.baidu.com/v2/api/?getapi&tpl=mn&apiver=v3&tt=1560648201405&class=login&gid=FF32A7E-718C-414C-A48A-F4CF60D97CF8&loginversion=v4&logintype=dialogLogin&traceid=&callback=bd__cbs__mj0low 返回的内容中发现了 token 值,不过我们想要获取 token 内容,还需要构建该请求中的必要参数,gid 和 callback参数。
gid 参数
打开相关 js 文件后,继续搜索 gid,看看 gid 是怎么产生的。
通过多次比对,发现 gid 由guideRandom这个函数产生的,接着在脚本中搜索这个函数。
最后找到了 gid 产生的函数,针对函数原型,我们可以利用 execjs 执行 js 代码,或者转换为 Python 代码。
callback 参数
经过多次测试,发现链接中的 callback 值都是以“bd__cbs__”开头,所以如果觉得搜索 callback 关键字太麻烦的话,可以搜索 “bd__cbs__”试一试。
在 js 文件中发现,callback 是由 getUniqueId 函数产生的,那我们继续往下找。
至此,获取 token 值的请求中的必要参数已经构建完毕,另外需要注意的是在发送 get 请求时,要将初次打开百度网页进行登录前的 cookie 保存下来,这次将继续使用,不然 get 请求响应内容不完整。
最终我们找到了 token 参数和 gid 参数,其中对于 callback 参数的分析,后续我们还会有所使用。那么接下来我们继续研究学习 rsakey 参数。
rsakey 参数
在搜索“rsakey”关键字没有结果的情况下,由于事先猜想可能使用了 RSA 加密,因此还会涉及到另一个关键字 pubkey,我们尝试着搜索一下看。(对于 RSA 非对称加密不了解的朋友,可以查看我之前的博客。)
对搜索的结果进行查看。
发现果然采用了 RSA 加密,并且发现了 rsakey 的踪迹。
最终发现了 pubkey 和 rsakey。接下来我们需要发送 get 请求,获取响应结果。我们需要分析https://passport.baidu.com/v2/getpublickey?token=9b76cbbb4933c882de7eb5d1b5da5ae3&tpl=mn&apiver=v3&tt=1560648209058&gid=FF32A7E-718C-414C-A48A-F4CF60D97CF8&loginversion=v4&traceid=&callback=bd__cbs__am8r4v 中必需的参数,细看发现就是我们上述步骤中找到的值,刚好可以拿来使用。记得 Headers 中的 Cookie 继续保留。
既然发现了 pubkey 参数值,那就看看是不是对 password 进行 RSA 加密。
password 参数
搜索 password 关键字,查看相关 js 文件。
结合上文中分析 rsakey 时看到的内容。
可以确定获取 rsakey 时一同返回的 pubkey 值就是 RSA 加密所需要的公钥,因此我们对输入的 password 进行 RSA 加密,返回加密后的数据。我是采用 Python 代码来实现 RSA 加密(关于 RSA 加密,可以参考我之前的博客)。
import base64
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5 #用于加密
def get_password(self):
with open('pubkey.pem','rb') as f:
pubkey = f.read()
rsakey = RSA.import_key(pubkey)
cipher = PKCS1_v1_5.new(rsakey)
passwd = base64.b64encode(cipher.encrypt(self.password.encode()))
return passwd
总结一下:目前我们已经对 token、gid、rsakey 以及 password 分析处理完毕,接下里的参数,我们下一篇再做详细分析。