前文
第一次写这么长的文章,语言组织可能有些不流畅,如果有什么不合理的地方请指出。 此分享只用于学习用途,不作商业用途,若有冒犯,请联系处理
逆向参数的分析流程
- 分析请求,找到参数
- 定位参数(搜索参数名,XHR断点,HOOk)
- 分析参数
- 补全构造代码
案例场景
目标网址:https://fanyi.youdao.com/ 我们用无痕模式打开谷歌浏览器,输入打开目标网址,然后打开开发者模式,输入需要翻译的内容。  我们只看异步请求的包,通过上图我们可以在不断输入内容时,浏览器会根据输入内容实时响应翻译结果,而图片中红线框的这个请求就是我们要学习的目标接口。
请求参数研究
我们随便点击一个请求看这个请求的参数相关信息  第一眼看这些参数我们可以明确一点就是smartresult ,from ,to ,client ,doctype ,version ,keyfrom 这几个参数时固定的;而i 是我们输入的内容,这个也是可以构造的;action 有两种值,一种是网站实时翻译类型FY_BY_REALTlME ,另一种是点击按钮触发的翻译类型FY_BY_CLICKBUTTION ;剩下salt ,sign ,lts ,bv 这四个参数是不固定的,根据salt ,lts 的数据格式可以判断这两个值跟时间戳有关,理论上只要找到这四个参数的生成规则我们就可以构造所有必要参数了。
我们再点击一下翻译按钮,看看还是用人生苦短,我用python 翻译的请求参数有啥不同,对比发现salt ,sign ,lts 这三个参数发生了变化,可以判定这三个参数是会随着请求重新构造生成的;而bv 这个参数不变判定要么是网站在某个地方写死了值,要么是两次请求中传入的某些东西是不变的所以这个值也不变,回顾我们进行的两次请求,发现真正不变的内容就是我们输入的翻译内容,我们可以输入其它内容看看bv 这个参数会不会变化。  通过上图可以确定bv 跟输入内容无关,到这里我们可以确定salt ,sign ,lts ,bv 这四个参数需要我们去逆向找到生成逻辑。
cookie研究
要想知道一个请求需不要cookie,只要请求时请求头不传入cookie,看看能不能正常响应拿到数据即可。  我们可以把这个网址的cookie信息全部清空,再次请求一次看看它的响应内容  进入全部请求内容,可以看到在没有cookie时第一个请求的就是我们的目标接口,看这个接口的请求头信息可以看到是有cookie信息的,而这个接口请求前面没有其它的请求,所以可以确定这个cookie信息不是由后端接口请求返回的,而是在接口请求前构造生成设置的,这样就确定了我们需要逆向找到cookie生成逻辑。
这样我们就明确了这个案例反爬的方式和反反爬的方向了,下面开始分享我的破解思路。
逆向破解
请求参数逆向破解思路流程
定位参数
XHR提取断点
在案例场景中我们已经分析并找到需要逆向的参数了,接下来我们需要定位到参数的逆向位置。由于目标网https://fanyi.youdao.com/translate_o?smartresult=dict&smartresult=rule 是xhr异步请求,我们可以直接设置XHR提取断点  按上图设置好xhr断点后点击翻译按钮,就会进入debugger模式  上图这个代码格式不方便阅读,我们可以点击图片左下方{} 进行代码格式化,格式化后会定位到发起xhr请求的位置,打上断点并执行下一步  可惜的是执行下一步后请求的执行结束了,可以确定无法通过XHR断点模式确定参数生成位置。
请求调用堆栈
通过查看请求调用堆栈我们可以知道这个请求的调用过程,其中send 调用位置就是我们通过XHR断点进去的位置,这一步对我们没有帮助,我们选择进入ajax方法。  进入ajax 调用位置后发现到这一步请求参数都已全部生成了,无法直接看到参数的生成过程  进入c 的调用位置发现也是如此,以此类推,进入t.translate 的调用位置,发现请求参数都是在这定义构造的,完美!  通过上图我们可以看到表单请求参数都在这里定义了,这样我们就定位到参数的生成位置了。
分析参数
观察我们定位参数后的代码,其实我们只需要找到最关键的salt ,sign ,lts ,bv 四个参数的生成逻辑即可,通过托图片我们可以看到这四个参数是通过r 对象得到的,而r 对象是有v.generateSaltSign 方法生成的,我们看一下这个方法的代码  可以确定以下逻辑:
- 参数
lts 是当前时间戳 n.md5 是网站自己封装的加密方法navigator.appVersion 是User-agent ,bv 通过加密User-agent 得到salt 跟lts 的值有关sign 通过固定加密得到,e 的值是我们要翻译的内容
补全构造代码
我们需要拿到参数生成的全部代码,一般逻辑是在node环境下,先运行入口函数或者代码,然后根据报错内容一步步补全构造代码。我们先看一下我们之前定位到参数的入口  理论上我们应该以这个方法作为参数生成入口,不过由于关键的四个参数是通过v.generateSaltSign 方法得到,同时虽然代码中调用了两次v.generateSaltSign 方法,但是实际上if判断内的代码是不会执行的,所以我们可以直接用v.generateSaltSign 方法作为参数生成入口。  将代码放到node化境下执行,把n.md5换成md5  报md5 is not defined 错误,找到md5的代码,添加进去继续执行  报h is not defined 错误,以此类推,补全缺的环境即可,最终执行效果  这样就能构造最关键的那四个参数了。
cookie参数逆向破解思路流程
到了这里其实我们可以按照请求参数的流程思路来定位查找,它们的逻辑是相似的。在研究cookie时我们确定了有两个参数说必要的且也是要逆向的:___rl__test__cookies ,OUTFOX_SEARCH_USER_ID_NCOO ,定位cookie参数的生成位置不好用XHR提取断点和请求调用堆栈处理,下面我们用另外一种定位方式。
全局搜索(Ctrl + Shift + F)
使用谷歌浏览器的全局搜索取定位些参数有时会相对方便点,特别是像cookie参数这么特别的格式。  我们使用OUTFOX_SEARCH_USER_ID_NCOO 进行全局搜索,可以看到只有一处出现这个参数,美滋滋!没有很多干扰。  如上图,可以看到最关键的两个参数都是在这里定义好的,我们清空网站cookie然后再发起请求进入调试模式  调试发现我们只要红色方框内的代码就行得到最终的值了,后面的代码不影响我们取值,还是老样子,将这些代码拿下来再node环境下运行,补全缺的环境。  运行补全好的代码后,我们会发现只有一个参数,其实另外一个参数是被覆盖了,不过我们知道它其实就是当前时间戳,只要添加进去就行。  这样我们就拿到了cookie参数了,现在我们已经成功破解了反爬,接下来要看看能不能请求到数据。。。
破解应用
部署node http接口
其实我们补全出来的代码量其实不多,也不复杂,有想法的同学可以了解代码逻辑简略代码过程,这里就不弄了。我们简单定义一个node http接口来接收破解生成的结果。
const http = require('http');
const sign_params = require('./create_sign_params');
const cookie = require('./create_cookie');
const qs = require('querystring');
const server = http.createServer()
server.on('request', function(req, res){
if (req.url.indexOf("/api/translate") != -1) {
var str = req.url.split('?')[1];
let obParams = qs.parse(str);
let keyword = obParams['key']
let result = sign_params.translate(keyword)
result['Cookie'] = cookie.translate_cookie()
res.writeHead(200, {'Content-type': 'application/json'});
res.end(JSON.stringify(translate_result))
} else {
res.end('api request failed')
}
})
server.listen('8080',function(err){
if(!err){
console.log("服务器启动成功了!!!!")
}
})
效果展示 
python调用实现
使用python去测试效果时,发现利用破解的参数没法请求成功数据,最终确定是cookie少了一个参数,不过这个参数是由后台服务返回的,所以我们需要先请求一次首页来拿到它。  测试时加进缺少的cookie参数后便能拿到数据了。 
总结
感谢您坚持看到这里,希望对您有所帮助。
|