最近开始了我的实习之旅,爬虫相关的, 然后就遇到某个网站在获取部分 URL 的时候,header 里会带有一个 token,根据内容能发现是 HMAC 加密的
没有 token 的时候一律会返回错误, 于是研究了下 JS 的逆行,找到了生成 token 的 function
理念就是打断点,先是针对于 url 的断点,找到是在哪个 js 文件中发生了 http 请求
然后顺着 call stack 一层一层往上找,看在哪里生成的 header
然后在 getAuthToken() 这里打点,能在环境变量里看到用于加密使用的 key
然后顺着找到 getAuthToken() 的源码,
1
2
3
4
5
6
7
8
9
| function (t){
var e=s.initConfig.getConfig("env"),
n=this.authKeys[e],
r=s.initConfig.getTimeOffset(),
i=(new Date).getTime()+r,
a=(t&&t.authAcl||"")+"/*",
u=(0,o.default)({},this.akamaiAuthconfig,{key:n,time:i,acl:a});
return new c.default(u).generateToken()
}
|
以及c.default(u).generateToken()
的源码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| var t = this.getIpField() + this.getStartTimeField() + this.getExprField() +
this.getAclField() + this.getSessionIdField() + this.getDataField(),
e = t + "" + this.getUrlField() + this.getSaltField(),
n = RegExp(this.delimiter + "$");
return t + "hmac=" + u.default.HmacSHA256(e.replace(n, ""), function(t) {
var e = "",
n = 0;
do {
var r = t[n] + t[n + 1],
o = parseInt((r + "").replace(/[^a-f0-9]/gi, ""), 16);
e += String.fromCharCode(o), n += 2
} while (t.length > n);
return e
}(this.key))
|
再根据实际需要进行简化,并进行比对,确认这个 function 正确运行。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| def gen_token(self):
def f(t):
e, n = "", 0
while(len(t) > n):
r = t[n] + t[n+1]
e += chr(int(re.sub(r"[^a-f0-9]", "", r+"") or "0", 16))
n += 2
return e
key = ""
t = int(time.time())
i = 6000
e = f"st={t}~exp={t+i}~acl=/*"
_hash = hmac.new(f(key).encode('latin-1'),
msg=e.encode('latin-1'), digestmod=sha256).hexdigest()
return f"{e}~hmac={_hash}"
|