Hi,大家好,欢迎大家参阅由IT猫之家精心制作的JS实战系列教学课程,我是作者叮当猫,在上期教学中,我们学习了如何快速分析基于Header授权加密协议,同时我们也初次接触到了钩子(hook)的概念,钩子在JS中可以说是较为高级的概念,如果大家有在操作系统中使用过钩子,那么你一定对这个不陌生,在windows中,我们常用的操作诸如,点击、拖拽、滑动、或者是输入,这些操作统统都是基于底层API通过发送消息实现的,比如我们要在某编辑框输入信息,我们会先取得子窗口的句柄(即选中窗体,按预定事件是否获取焦点等),然后才能向该句柄发送text指令,当CPU得到响应后会根据相关指令完成相应的操作,而钩子在这一发送的过程中可以作为一个中间人为您监听、篡改报文、或拦截报文等作用,当然它不是必须的,除非你想要,事实上它就是一种消息中断机制,如上述所言,它可以监听一切传送的内容,那么在JS中,它的作用也是类似的,今天我们将会学习如何通过钩子快速定位到Cookie加密协议入口,在此之前如果您是第一次观看本教学,欢迎前往:网络爬虫频道查阅,本期我们就一起来探讨下,在日常爬取数据的过程中,当我们遇到Cookie加密授权时该如何处理,我们将以越捷航空官网作为演示的目标,如大家有不懂的欢迎留言,或加入我们的QQ技术交流群探讨:544185435
【网络爬虫教学】一分钟带你快速寻找JS加密入口-视频版
由于国内频道遭版权问题封禁,上传不了,所以目前仅上传Youtube,如需观看视频请前往源站:IT猫之家_JS实战系列之Cookie加密协议分析
步骤一
需准备Fiddler(抓包用)、Chrome(调试与分析)
我们打开Fiddler,为了方便我们分析数据,建议大家配置过滤器,仅过滤我们需要的信息,如上图我们将面板切换至Filters项,勾选“Use Filters”旁边的复选框,Hosts选项分别选择:1. Show only Internet Hosts、2. Show only the following Hosts;并在编辑框中输入“*. 要过滤的URL(不包含前缀) ”以分号结束,如越捷航空的URL为: https://www.vietjetair.com/ 则规则应写成:*. vietjetair.com ;意为泛匹配的意思,填写完毕后点击右上角的“Changes not yet saved.” 保存。
步骤二
打开越捷航空官网、选择航班进行搜索、通过Fiddler抓包后分析相关请求,并寻找出携带加密Cookie的接口
我们打开越捷航空的官网,并确定一下Fiddler是否正常能正常过滤出我们预设的域名。
随便输入航线、日期,这里我们选择单程,也可以按默认,选择完毕后点击查询航班按钮。
点击跳转后的结果页面是这样的,可能存在跳转中断问题,即跳转后空白无响应,这是因为网站监测到你的流量异常,重新多试几遍即可,或者换浏览器。
如果您正确的配置了Fiddler,应该会出现如上图所述的请求链接,也就是说我们要分析的加密就在上述的链接之中。
在分析请求之前,我们必须先找到实际的请求URL有哪些,如果您此前有做过航司爬虫方面的工作,我相信您肯定一眼就能看出哪个是请求的接口了,这个站的请求接口为:https://booking.vietjetair.com/ameliapost.aspx?lang=zh 我们可以通过Fiddler的WebForms面板查看,如果您不知道如何找到该面板,请在Fiddler中切换至Inspectors项,它的子菜单栏中就能看到WebForms选项了,通常查询接口包含始发站点(通常三字码)、到达站点(通常三字码)、日期、货币、人的类型(成人/小孩/婴儿)、与其它必要数据;
我们将面板切换至Cookies选项,通过分析,我们可以在:https://booking.vietjetair.com/TSPD 开头的这个请求接口中看到一串已“TSdc75a61a_74”开头的Cookie,而这串Cookie正是我们本次要分析的目标字段,当然如果你分析下去后,你会发现,其实这个字段仅仅只是开始而已,后面有好几个类似的字段都需要我们去解密,之所以我会以这个站作为教学的目标站点,因为它足够的复杂。
步骤三
开启Chrome Conse、尝试在控制台中全局搜索与“TSdc75a61a_74” 相关的请求、通过Mouse断点进行调试
跟以往一样,我们可以先去尝试下通过关键词搜索方式在Chrome控制台中进行全局匹配,如果您此前还未曾使用过Chrome Console,欢迎查看之前的文章后再回来看,很遗憾,我们在找遍所有相关字段后都没有匹配到一条合适的URL,那么极有可能这个字段名称是由JS动态生成的了,也就是说,这条路行不通。
俗话说,山路不通走水路,通过上面的判断,我们知道了Cookie加密的字段名称极有可能是动态生成的,所以我们不能使用该方式,改用Mouse断点法测试一下吧!首先我们打开控制台右侧的“Event Listener Breakpoints”选项,并找到“Mouse”子项,并在“click”旁边的复选框中勾上,用以监听鼠标的点击事件(这实际上就是一个钩子,而这个钩子是Chrome内置的)。
当我们在页面上点击查询航班按钮后就会发现网页被断了下来,并没有继续跳转,我们点击上图指向的花括号,用以美化代码,让我们分析起来更清晰些。
在经过反反复复的尝试之后,我们就会发现,根本没法正确命中断点,换句话说,根本不能找到入口,因为这个站的加密在页面跳转的同时就已经删除了加密代码,所以一旦跳转,我们再也找不到加密的入口。
步骤四
编写钩子函数,监听Cookie接口信息的收发、结合Chrome extension实现信息中断与拦截机制
在经过上述步骤的尝试,我们总结出一个结论,就是每种调试方式都不是万能的,它们仅仅只是一种方式,事实上使用Mouse断点方式确实可行,只是它需要花费大量的时间去调试、失败、调试,再失败再调试,这个过程会让您调试到怀疑人生,那我们何不以更取巧的方式来实现曲线救国呢?答案是肯定的,既然这个加密是通过Cookie实现的,那么我们完全可以通过自定义钩子来监听它,这里要先声明一点:钩子也不是万能的,只有在目标函数加密时使用到了内置函数才可以使用,比如上一期教学中的Header授权加密,它采用了setRequestHeader接口,所以我们可以监听并拦截该接口的收发信息,同理这里我们也可以监听Cookie的接口,实现方式也非常的简单,如下。
inject.js文件
var code = function(){
var org = document.cookie.__lookupSetter__('cookie');
document.__defineSetter__("cookie",function(cookie){
if(cookie.indexOf('TSdc75a61a')>-1){
debugger;
}
org = cookie;
});
document.__defineGetter__("cookie",function(){return org;});
}
var script = document.createElement('script');
script.textContent = '(' + code + ')()';
(document.head||document.documentElement).appendChild(script);
script.parentNode.removeChild(script);
这里我们重写了Cookie的lookupSetter接口,当匹配到包含TSdc75a61a的Cookie时,则直接断下来,所以我们要确定被加密的字段会经过该接口,方可进行拦截。
manifest.json 文件
{
"content_scripts": [ {
"js": [ "inject.js"],
"matches": [ "http://*/*", "https://*/*","<all_urls>"]
} ],
"manifest_version": 2,
"name": "CookieHook",
"permissions": ["tabs"],
"version": "0.1"
}
在完成JS文件的编写后,我们还需额外声明一个manifest文件,用以声明这是一个Chrome extension,当两个文件都编写完成后将其放入一个文件夹中,(两个文件必须同一目录),并为目录取名“CookieHook”,到此完成扩展的编写以上仅仅是一个最简单的案例,其它功能可自行参考扩展官网教程。
步骤五
启用CookieHook扩展插件进而捕获加密数据从而实现快速寻找切入口的目的
在chrome的url中输入: chrome://extensions/ 然后启用开发者模式,点击加载已解压的扩展程序,选择刚创建的目录(是目录),按确定后将会看到如上图的扩展项。
回到越捷航空首页,并打开控制台(可按F12唤出),我们再次尝试输入航线,然后点击查找航班,如无意外,网页便会断了下来,然后我们将鼠标移到cookie中,便可清晰的看到,我们要找的加密字段了。
通过在堆栈中寻找源,我们不难发现,它的入口就是:J(Z, _, J)这个函数,当然这个函数是可变的,根据我们分析的规律,它是间隔2小时更新一次算法,(应该说变更一次模板)如果您看到的跟我的不一样,请不用怀疑,它就是加密的入口,我们清晰可见:zL这个变量中得到的是字段名“ TSdc75a61a_74 ”那不就是我们要找的么,从而我们可以证实了这个字段名是动态生成的想法。
总结
以上为本期教学的所有内容,主要讲解了如何通过自定义钩子函数实现快速寻找加密函数入口,并且我们也尝试了通过不同的调试方式进行定位,需要注意的是,钩子函数并非所有场景都能使用,只有当目标函数采用了内置API才能对其进行监听,当然这个规定是死的,事实上我们完全可以通过proxy来实现监听任意函数而不仅仅只是趋限于内置的函数,大家懂我意思吧?好了,本期教学到此暂告一段落,咱们下期再见!