爬虫对抗:ZLibrary反爬机制实战分析 (二) - 破解动态请求签名与参数加密

免责声明:本文仅供技术交流与安全研究使用,严禁用于任何非法抓取、商业牟利等破坏目标网站正常运行的行为。

在系列的第一篇文章中,我们通过环境伪装和无头浏览器技术,成功突破了 ZLibrary 的前端反爬盾,拿到了可以正常访问 HTML 页面的权限。然而,对于一个现代化的 Web 应用,核心数据(如搜索结果、书籍详情、下载链接)通常是通过 Ajax/XHR 异步加载的。

当你满怀欣喜地使用拿到的 Cookie 去请求 ZLibrary 的 API 接口时,却大概率会再次碰壁,收到 401 Unauthorized400 Bad Request。打开网络面板一看,请求头中多出了一些奇怪的字段(例如 X-SignatureX-TimestampX-Req-Token),并且 POST 的表单数据竟然是一串毫无规律的乱码。

这就是我们本篇要攻克的堡垒:API 请求签名与参数动态加密机制

一、 请求分析:寻找加密的蛛丝马迹

在浏览器控制台的 Network 面板中,我们抓取一个搜索请求。观察其 Request Headers 和 Payload。

特征 1:动态请求头 通常会包含时间戳和一个长度固定的哈希字符串(Signature)。

  • X-Timestamp: 1711234567 (当前的 UNIX 时间戳)

  • X-Signature: a8f3b2...c9d1 (看起来像是 MD5 或 SHA256)

  • X-Nonce: 随机字符串,用于防止重放攻击 (Replay Attack)。

特征 2:参数加密 原本应该是 {"query": "python", "page": 1} 的 JSON 格式,变成了:

  • data: U2FsdGVkX1+9x/k... (典型的 AES 加密后的 Base64 编码,或者是自定义混淆格式)。

如果签名算法不对,或者参数没有正确加密,服务器直接在网关层就会将请求丢弃。

二、 逆向解析:抽丝剥茧找算法

要伪造这个请求,我们就必须找出生成 Signature 和加密 data 的 JavaScript 代码。

1. XHR 断点拦截

这是逆向 API 最有效的手法。在 Chrome DevTools 的 Sources 面板右侧,找到 XHR/fetch Breakpoints。添加一个包含请求 URL 关键字的断点(比如 /api/search)。 触发搜索操作,浏览器会瞬间停在发起 XMLHttpRequest.send() 或是 fetch() 的那行代码上。

2. 调用栈回溯 (Call Stack Trace)

停在发送网络请求的地方还不够,此时数据通常已经加密好了。我们需要顺着右侧的 Call Stack(调用栈)一层层往上回溯。 不断点击调用栈中的上一层函数,观察局部变量的作用域(Scope)。你会发现某个时刻,原始的明文 JSON {"query": "python"} 存在于变量中,然后经过了一个类似于 Object(r.a)(t) 这样的恶心函数调用,就变成了乱码。

3. Webpack 模块提取与解包

现代前端往往使用 Webpack 或 Vite 进行打包。刚才提到的 Object(r.a) 其实就是 Webpack 加载的某个加密模块。 难点 :直接抠代码会遇到环境依赖问题(缺少其他模块)。 解决思路

  • 全扣法 :把整个 Webpack 的入口 window.webpackJsonp 结构扣下来,在本地 Node.js 环境中模拟执行,暴露出加密函数。

  • 打桩插桩 :通过编写 Chrome 插件或者使用抓包工具(如 Charles/Mitmproxy)拦截 JS 文件,在加密函数的入口和出口处加上 console.log(),动态打印出其加密过程和密钥。

三、 算法还原:AES 与 HMAC 的交响曲

经过漫长的抠代码和调试,我们通常会发现其加密与签名的本质逻辑:

1. 参数加密 (通常是对称加密 AES)

  • 密钥 (Key):通常通过前端的某个全局变量,或者由服务器在初始 HTML 源码中下发,亦或是通过时间戳和某个固定盐值 (Salt) 计算得出。

  • 向量 (IV):为了保证每次加密结果不同,IV 往往是随机生成的,并附加在密文前或者作为单独的 Header 传输。

  • 算法往往是 AES-128-CBC 配合 Pkcs7 填充。

2. 请求签名 (HMAC) 为了防止中间人篡改数据,ZLibrary 会要求对请求进行签名。计算公式大致如下: Signature = HMAC_SHA256(SecretKey, URL_Path + Timestamp + Nonce + MD5(RequestBody))

四、 可复用的绕过思路:Python 还原与 RPC 方案

面对找出的加密逻辑,我们有两种可复用的应对方案。

方案一:纯 Python 算法还原 (推荐,性能最高)

如果我们彻底搞懂了 JS 里的 AES 和 HMAC 逻辑,以及 Key 的生成规则,我们就可以脱离浏览器,用 Python 的 cryptographyPyCryptodome 库完全重写一遍。

复制代码
# 伪代码:Python 还原 ZLibrary 请求签名与加密过程
import time
import hashlib
import hmac
import json
import base64
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad

# 假设逆向分析出的常量和盐值
SECRET_KEY = b"zlib_super_secret_salt_2024"
AES_KEY = b"dynamic_key_from_js_1234" # 实际情况中可能需要动态计算
AES_IV = b"1234567890123456"

def encrypt_payload(data_dict):
    cipher = AES.new(AES_KEY, AES.MODE_CBC, AES_IV)
    json_str = json.dumps(data_dict)
    padded_data = pad(json_str.encode('utf-8'), AES.block_size)
    encrypted = cipher.encrypt(padded_data)
    return base64.b64encode(encrypted).decode('utf-8')

def generate_signature(path, timestamp, payload_str):
    # 构造待签名的基础字符串
    message = f"{path}|{timestamp}|{payload_str}"
    # 使用 HMAC-SHA256 生成签名
    signature = hmac.new(SECRET_KEY, message.encode('utf-8'), hashlib.sha256).hexdigest()
    return signature

def fetch_data():
    timestamp = str(int(time.time()))
    api_path = "/api/v1/search"
    payload = {"query": "deep learning", "limit": 20}
    
    encrypted_data = encrypt_payload(payload)
    sign = generate_signature(api_path, timestamp, encrypted_data)
    
    headers = {
        "X-Timestamp": timestamp,
        "X-Signature": sign,
        "Content-Type": "application/json"
    }
    
    # 使用 requests 发送完全伪造的合法请求
    # response = requests.post("[https://zlibrary-domain.com](https://zlibrary-domain.com)" + api_path, headers=headers, json={"data": encrypted_data})

方案二:浏览器 RPC (Remote Procedure Call) 方案

如果 JS 代码混淆程度太深(比如使用了高度定制的 WebAssembly 或者 OLLVM 混淆),纯算法还原的时间成本过高,我们可以采用 RPC 方案。

原理是:使用 Playwright 挂载真实的 ZLibrary 页面,在页面内注入 WebSocket 客户端。Python 脚本作为服务端。当 Python 需要发请求时,通过 WebSocket 把明文参数发给浏览器,利用浏览器页面内自带的、现成的 JS 加密函数进行加密和签名,把结果传回给 Python,Python 再去发送 HTTP 请求。

这种方案完美绕过了逆向算法的过程,降维打击,实现真正意义上的"可复用"。

总结:突破了请求签名与加密,我们已经可以将 ZLibrary 的数据转化为结构化的 JSON。但不要高兴得太早。当我们开始高并发抓取时,网络层的死神正在逼近。下一篇,我们将探讨最后也是最难的关卡:TLS 指纹与 IP 频率风控的突破。

相关推荐
vx_biyesheji00012 小时前
计算机毕业设计:Python全栈图书数据挖掘与可视化看板 Django框架 爬虫 当当图书 Pandas 可视化 大数据 大模型 书籍(建议收藏)✅
爬虫·python·机器学习·数据挖掘·django·毕业设计·课程设计
B站_计算机毕业设计之家17 小时前
计算机毕业设计:Python当当网图书数据全链路处理平台 Django框架 爬虫 Pandas 可视化 大数据 大模型 书籍(建议收藏)✅
爬虫·python·机器学习·django·flask·pandas·课程设计
2401_8916558120 小时前
爬虫对抗:ZLibrary反爬机制实战分析的技术文章大纲
爬虫
q_354888515320 小时前
计算机毕业设计:Python当当网图书大数据分析平台 Django框架 爬虫 Pandas 可视化 大数据 大模型 书籍(建议收藏)✅
大数据·爬虫·python·机器学习·数据分析·django·课程设计
2401_884662101 天前
爬虫对抗:ZLibrary反爬机制实战分析技术文章大纲
爬虫
CDN3601 天前
爬虫对抗:ZLibrary反爬机制实战分析及360CDN解决方案可行性论证
爬虫·网络安全
进击的雷神1 天前
展位号后缀清理、详情页JS数据提取、重试机制控制、地址字段重构——美国NPE展爬虫四大技术难关攻克纪实
javascript·爬虫·python·重构
B站计算机毕业设计之家1 天前
计算机毕业设计源码:Python图书数据智能采集与可视化大屏 当当网 Django框架 爬虫 Pandas 可视化 大数据 大模型 书籍(建议收藏)✅
爬虫·python·机器学习·信息可视化·django·pandas·课程设计
嫂子的姐夫1 天前
042-spiderbuf第C7题
爬虫·python·逆向