前言语
js参数加密,越来越多的网站进行数据传输时不使用明文传输而改为使用js通过一定的规则的转换后,后端进行解密,或者对铭文数据进行转换后,将值单独放在另一个字段,后端通过相同的方法进行转换后与我们传过去的值进行对比,对比不一致就会导致本次请求错误。
百度翻译就是采用后面的验证方法。
请求参数分析
经过多次请求对比发现,sign值是跟随query变化而变化的。
通过charles搜索token的值,发现该值是写在百度翻译页面的源码内,很容易获取。
动态分析参数生成方式
定位参数生成的位置
通过charles搜索sign,找到该请求体构造的代码块即ajax发送post请求的代码块。
很容易定位到,post请求的代码在aio_09ae08b.js中。
断点调试
使用chrome进行调试。
随便输入一个词进行翻译,触发js代码
发现sign是将待翻译的词传入G函数后生成的。
按F11或者点击该按钮进入函数。
在return处下断点,看最后返回了什么
所以return返回的结果为 653283.857298
我们抓包查看发送给服务器的数据是什么
结果一致。
使用python生成sign
第一种方式-读懂js代码,翻译成python
以上代码是可以直接翻译成python代码的,而且并不麻烦,简单的数据运算。
使用执行js的包
- pyv8
- pyexecjs
- js2py
js2py容易出错,pyv8不支持python3,所以我们使用pyexecjs
安装
pip install pyexecjs
使用node.js运行环境,所以需要下载安装node.js,并新增环境变量。
# -*- coding: utf-8 -*-
# @Time : 2019/7/23 15:57
# @Author : Conderfly
# @Email : coderflying@163.com
# @File : sign_js.py
import execjs
js = r'''
var i = "320305.131321201"
function n(r, o) {
for (var t = 0; t < o.length - 2; t += 3) {
var e = o.charAt(t + 2);
e = e >= "a" ? e.charCodeAt(0) - 87 : Number(e),
e = "+" === o.charAt(t + 1) ? r >>> e : r << e,
r = "+" === o.charAt(t) ? r + e & 4294967295 : r ^ e
}
return r
}
function a(r) {
var t = r.match(/[\uD800-\uDBFF][\uDC00-\uDFFF]/g);
if (null === t) {
var a = r.length;
a > 30 && (r = "" + r.substr(0, 10) + r.substr(Math.floor(a / 2) - 5, 10) + r.substr(-10, 10))
} else {
for (var C = r.split(/[\uD800-\uDBFF][\uDC00-\uDFFF]/), h = 0, f = C.length, u = []; f > h; h++) "" !== C[h] && u.push.apply(u, e(C[h].split(""))), h !== f - 1 && u.push(t[h]);
var g = u.length;
g > 30 && (r = u.slice(0, 10).join("") + u.slice(Math.floor(g / 2) - 5, Math.floor(g / 2) + 5).join("") + u.slice(-10).join(""))
}
var l = void 0, d = "" + String.fromCharCode(103) + String.fromCharCode(116) + String.fromCharCode(107);
l = null !== i ? i : (i = o.common[d] || "") || "";
for (var m = l.split("."), S = Number(m[0]) || 0, s = Number(m[1]) || 0, c = [], v = 0, F = 0; F < r.length; F++) {
var p = r.charCodeAt(F);
128 > p ? c[v++] = p : (2048 > p ? c[v++] = p >> 6 | 192 : (55296 === (64512 & p) && F + 1 < r.length && 56320 === (64512 & r.charCodeAt(F + 1)) ? (p = 65536 + ((1023 & p) << 10) + (1023 & r.charCodeAt(++F)), c[v++] = p >> 18 | 240, c[v++] = p >> 12 & 63 | 128) : c[v++] = p >> 12 | 224, c[v++] = p >> 6 & 63 | 128), c[v++] = 63 & p | 128)
}
for (var w = S, A = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(97) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(54)), b = "" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(51) + ("" + String.fromCharCode(94) + String.fromCharCode(43) + String.fromCharCode(98)) + ("" + String.fromCharCode(43) + String.fromCharCode(45) + String.fromCharCode(102)), D = 0; D < c.length; D++) w += c[D], w = n(w, A);
return w = n(w, b), w ^= s, 0 > w && (w = (2147483647 & w) + 2147483648), w %= 1e6, w.toString() + "." + (w ^ S)
}'''
def sign(keyword):
return execjs.compile(js).call("a",keyword)
运行测试结果,与post请求中的一致
请求测试
结束。