首先我们先来看一下,下面这张图是笔者近期测试遇到的问题,那就是程序每次生成请求都会生成signature的验签,该验签生成方式暂不可知,唯一知道的就是用一次就失效,这对测试的成本造成了很不好的影响,那么我们想要突破防护,最起码也要知道,这个signature是怎么生成的,他的算法是什么?
暂且忽略加密,因为实际上网站后面的内容加密部分并不多,我们主要是突破requestid、signature即可;想要知道requestid的生成、signature的生成,我们就需要对程序进行动态调试,动态调试我们建议使用google浏览器,火狐浏览器会出现卡顿......
首先F12打开调试器,然后全局搜索signature即可
双击选中的结果,然后代码格式化一下
CTRL + F 在当前app.xxx.js文件内再次搜索signature关键字,寻找我们觉得像的
此时,我们发现有个东西很像了
e.headers.signature = Object(u["a"])(encodeURIComponent(c.join(";"))),
我们直接在这里打断点看看
我们暂时无视上面的值,我们直接定位到这个代码的位置,该代码由多个函数组成,我们可以在控制台看一下他们是干什么的
首先看一下e里的内容
可以看到,e.headers
里是没有signature的,说明此时signatuer还没来得及生成
继续程序(F10),观察signature
此时signature生成,说明我们的断点没问题;
此时回顾一下整个函数内容
我们拆分一下函数内容,首先是c c现在是一个数组类型,暂时里面包含了两个内容,一个是URL一个是Requestid;这两个是怎么来的我们稍后看;
c.join(“;”)
是将两个字符串拼接,用分号分割
encodeURIComponent(c.join(";"))
其实就是将特殊符号抓换成url编码,这样json类型就变成了字符串类型了
最后一步,u["a"](encodeURIComponent(c.join(";")))
u[“a”]()
是关键函数,这个函数将收到的两个字符串合并在一起进行加密,最后生出了signature这个东西,但是我们并不知道里面的算法是什么
但是看他的位数,我们可以猜测大致的算法,这里推荐大家可以去调试,也可以猜解
随便打开一个在线的sha1加密,将我们拿到的字符串放进去,发现生出来的值与调试器里的验签值是一样的,那么我们可以确定,程序是sha1加密的
获取到了算法,我们接下来就需要知道,c的值是怎么来的(就是URL/Request),因为该程序会根据不同的场景,即登陆前、登录后(登陆后产生token)、有body和无doby
因为我们知道,关键的参数其实就是c,恰巧我们看到了程序上面有很多的c.push
看字面也能才出来这是再往里面加参数,所以这里可以将所有的c.push
打断点
此时重新走一遍,这一次我们将分为3个场景对程序进行调试
登陆前
登录后
存在token且有body参数
登陆前的调试,我们需要确定requsetid、url怎么来的
第一步,程序首先生成了一个l ,这个l 其实就是数据包请求中的requestid;大家可以跟进这个d[“w”]()
函数,核心代码如下,大家如果不知道是干啥的也不要紧,现在chatgpt这么现金,大家可以直接把代码粘进去生成一个python代码就行,这个代码其实就是生成requestid的,在python中有一个标准的库,uuid库
此时第一个被压入的就是l 也就是我们随机生成的requestid
我们步过后,此时程序进入下一步
if (c.push(Object(d["i"])()),
e.data && c.push(JSON.stringify(e.data))
不知道这个程序是干啥的,那么就直接放到控制台里
我们可以看出来,此时d[“i”]()
函数返回空,因为token现在是没有的
e.data()
其实就是我们的登录请求数据包体,JSON.string
其实就是将数据包转换成了字符串类型
接下来进入到下一步
t.queryVal(f)
t.queryVal(a)
这两步应该是判断,url参数后边有没有东西,比如说 xxx/login?id=1
有的话就会给过滤掉,t.queryVal(a)
就是拿到url
我们现在查看一下c的内容
此时c里有3条,分别是requestid、body、url
c.sort()
其实就是将c重新排序
我们发现此时的顺序是
url + requestid + body
对应程序的就是
t.queryVal(a) + d[“w”]() +e.body && JSON.stringify(e.data)
最后回到
e.headers.signature = Object(u["a"])(encodeURIComponent(c.join(";")))
我们可以看出来,正如我们所想的那样,那么这个时候我们就可以看到,signature生成规则如下
这里面没有看到token,不过不要紧,我们现将登录请求通过,然后再看看登录后的请求
登录后生成token后,我们直接略过前面的调试过程
c.push(l)
Object(d["i"])()
获取token
c.push(JSON.stringify(e.data)
c.push(t.queryVal(a))
一直走到e.headers.signature
c.sort()
e.headers.signature = Object(u["a"])(encodeURIComponent(c.join(";")))
至此,全部捋顺
sha1(URL + token + requestid + body)
带token、带body
写在末尾:
致谢:AirSky
感谢来自实验室的好兄弟的指点
本文由AirSky 、Vlan911联合输出