案例地址:qizhidao.com
请求参数
acw_tc和x-web-ip
清空cookie后,初次请求会返回acw_tc和x-web-ip。
后续的请求中会携带,一些接口不带也行。
wz_uuid
wz_uuid似乎是游客ID,全局搜索可定位到wz_uuid。
调试一下
主要是 z.i
function O(t) {
var e = (t || window.navigator.userAgent || Object(a.m)(4, 8)) + (new Date).getTime() + Object(a.m)(4, 8);
return s()(e)
}
先看 a.m
function a_m(t, e, n) {
var r, o = "";
void 0 === t && (t = 6),
"string" == typeof e && (n = e),
r = e && "number" == typeof e ? Math.round(Math.random() * (e - t)) + t : t,
n = n || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < r; i++) {
var a = Math.round(Math.random() * (n.length - 1));
o += n.substring(a, a + 1)
}
return o
}
继续看一下 s()(e)
看起来是先生成userAgent+时间+随机字符的 e,然后通过s()方法对 e 进行MD5
拿到工具站测试下, 地址:cnlans.com/lx/tools
最后,把md5结果和 "X/" 拼接。
wz_uuid 代码如下:
const crypto = require('crypto');
window = {}
window.navigator ={
userAgent:'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
function md5(data){
return crypto.createHash('md5').update(String(data)).digest('hex');
}
function z_i(t) {
var e = (t || window.navigator.userAgent || Object(a_m)(4, 8)) + (new Date).getTime() + Object(a_m)(4, 8);
return 'X/'.concat(md5(e))
}
function a_m(t, e, n) {
var r, o = "";
void 0 === t && (t = 6),
"string" == typeof e && (n = e),
r = e && "number" == typeof e ? Math.round(Math.random() * (e - t)) + t : t,
n = n || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < r; i++) {
var a = Math.round(Math.random() * (n.length - 1));
o += n.substring(a, a + 1)
}
return o
}
console.log(z_i(undefined))
响应解密
比如页面:https://www.qizhidao.com/check?
全局搜索 decrypt
触发请求,进入调试状态。
观察发现,AES加密,key为 "xc46VoB49X3PGYAg", mode为ECB, padding为 Pkcs7
Python实现
【温馨提示:此处隐藏内容需要登录后才能查看!】
防问屏蔽
阿里云盾安全拦截:很抱歉,由于您访问的URL有可能对网站造成安全威胁,您的访问被阻断。
经查看,被检测的请求ID是由浏览器环境 MD5后生成。
最后生成的ID应该是和访问IP进行关联的,该站点多次不带访问ID会被拦截,访问频繁也会被拦截。
所以待该站点出现拦截后,更换 游客ID 和 访问IP 可继续访问。
代码整合
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import requests,execjs
def decrypt(data):
html = base64.b64decode(data)
key = b'xc46VoB49X3PGYAg'
aes = AES.new(key=key, mode=AES.MODE_ECB)
info = aes.decrypt(html)
decrypt_data = unpad(info, 16).decode()
return decrypt_data
def webid():
js = '''
const crypto = require('crypto');
window = {}
window.navigator ={
userAgent:'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
}
function md5(data){
return crypto.createHash('md5').update(String(data)).digest('hex');
}
function z_i() {
var t = undefined;
var e = (t || window.navigator.userAgent || Object(a_m)(4, 8)) + (new Date).getTime() + Object(a_m)(4, 8);
return 'X/'.concat(md5(e))
}
function a_m(t, e, n) {
var r, o = "";
void 0 === t && (t = 6),
"string" == typeof e && (n = e),
r = e && "number" == typeof e ? Math.round(Math.random() * (e - t)) + t : t,
n = n || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
for (var i = 0; i < r; i++) {
var a = Math.round(Math.random() * (n.length - 1));
o += n.substring(a, a + 1)
}
return o
}
'''
exec = execjs.compile(js)
return exec.call('z_i')
h = {
"accept":"application/json, text/plain, */*",
"content-type":"application/json;charset=UTF-8",
"origin":"https://www.qizhidao.com",
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
"user-agent-web":webid(),
}
data = {"content":"中科大数据研究院","app_date_list":[],"cur_legal_status_list":[],"out_types":[],"pageSize":20,"current":1,"orderColumn":"_score","orderType":"DESC","platform":1}
r = requests.post('https://www.qizhidao.com/api/qzd-bff-ips/patent/search/list',headers=h,json=data)
print(decrypt(r.json()['data1']))