前言
头条的加密参数_signature其实可以通过搜索来直接定位到关键位置,我们换种定位的方法
定位
先查看下堆栈,直接在第一个XMLHttpRequest.send的位置下上断点,然后下拉触发断点
这个位置还有其他请求,这里只看/api/pc/list/feed
,可以看到this的openArgs里面的uri参数已经包含了_signature,所以我们追上面的堆栈
前面的那些栈就不看了,因为并没有找到this.openArgs被赋值的地方,直接看下面的这个
在var h = new XMLHttpRequest;
下上断点,并取消之前所有的断点
可以看到url是在h.open这一行被赋值的,e.params就是请求的参数
e来源于上面的参数,在第一行打上断点,然后往前翻堆栈
同样在上一层的第一行打上断点,因为e又是来源于参数
这时候堆栈没有上一层了,说明是异步调用的,看Promise.then(async) 里的调用栈。点第一个c.request
关键代码在上图中的框起来的那个循环(当然这个是后话,因为单从这里无法判断这里就是加密的关键位置,需要单步走下去看看e到哪里生成的),下面的代码是先往t数组中push一些函数,unshift和push是一个意思,只是加到数组的头部
this.interceptors.request.forEach((function(e) {
t.unshift(e.fulfilled, e.rejected)
}
)),
this.interceptors.response.forEach((function(e) {
t.push(e.fulfilled, e.rejected)
}
))
然后进入循环,打上断点,可以看到n就是Promise
for(;t.length;){
n = n.then(t.shift(), t.shift());
}
上面的代码修改成同步的,数组的函数就是this.interceptors.request
和this.interceptors.response
两个数组里面的函数
for(;t.length;){
// 弹出t数组头部的第一个元素
var fulfilled = t.shift();
// 执行这个函数
fulfilled();
var rejected= t.shift();
rejected();
}
可以看出t里面有十个元素,其中有五个函数,点进去第一个看看代码
来到了下面的代码,因为是请求加密所以我们只看interceptors.request
就可以了,正常的话是在所有的interceptors.request函数里都打上断点,但是下面的代码已经很明显出现了_signature: n
,所有先在这一行打上断点
加密代码就是var n = I(F.getUri(e), e);
这个,F.getUri(e)的值是/api/pc/list/feed?channel_id=0&max_behot_time=1676120482&category=pc_profile_recommend&aid=24&app_name=toutiao_web
,这个就是url里面的uri。e是一个包含很多内容的对象,先不管,先进去I函数里面看看
函数看起来有很多行,简化一下就下面几行
function I(e, t){
var r = "https://www.toutiao.com";
var o = {
url: r + e
};
return window.byted_acrawler.sign(o);
}
关键就在于window.byted_acrawler.sign这个函数,鼠标悬上面,然后点进去看一下
进到acrawler.js
也就是说window.byted_acrawler.sign是这个js里面导出的函数,那么只需要运行这个js就可以得到window.byted_acrawler对象了
新开一个标签页,在snippets创建一个脚本,然后把acrawler.js内容复制到里面,可以看到最开始window.byted_acrawler是没有值的,运行这个js后就出现了值
测试一下加密,发现加密的结果短了很多。这里看过其他文章就知道,是因为少了cookie,只要加上cookie,结果就是长的
补环境
这个就不说了,我也是用的别人的框架。