接口参数逆向:加密与签名还原思路
前置知识
本文基于模型知识整理,仅讨论学习与授权场景下的通用方法原理;不得用于绕过付费墙、账号风控或未授权系统(红线见 kp-004)。
一句话定义
参数逆向是分析前端 JS、还原请求签名/加密参数生成逻辑的过程;常见形态远比想象中简单——大多是「时间戳 + 固定盐 + 哈希」的组合。
为什么重要
不少高价值接口以签名作为门禁。能读懂签名构造,就走得上接口路线;读不懂则只能退回慢十倍的浏览器路线。逆向思维同时也训练你从「黑盒调用者」升级为「能读前端代码的工程师」。
前置知识
kp-014(已定位到带加密参数的接口)。
核心概念
- 常见参数族:
timestamp(时间戳)、nonce(随机数)、sign/signature(哈希签名)、token(会话/设备凭证)。 - 典型构造:
sign = md5(sorted(params) + secret)、sign = md5(timestamp + fixed_salt)、sign = base64(aes_encrypt(payload))。 - 定位手段:Sources 面板全局搜索参数名 → XHR 断点 → 调用栈回溯生成函数。
- 执行手段:还原成 Python;或把相关 JS 函数抠出来交给 Node/PyExecJS 本地执行。
原理与机制
通用分析流程(以「sign 参数从哪来」为主线):
1. Network 确认参数 → Sources 全局搜索 "sign"(参数名最易暴露)
2. 命中处打 XHR/条件断点 → 重新触发请求 → 断在生成点
3. 读函数: 输入是什么(参数集/时间戳) 混了什么盐 输出什么编码
4. Python 复刻 → 与真实值比对 → 不一致则继续读调用链
5. 复杂混淆(变量名压缩/控制流平坦化) → 抠函数给 Node 执行, 不硬啃
最常见的一类(占多数场景)Python 复刻示例:
import hashlib, time
def make_sign(params: dict, ts: int, salt: str) -> str:
raw = "".join(f"{k}={params[k]}" for k in sorted(params)) + ts + salt
return hashlib.md5(raw.encode()).hexdigest()
params = {"page": 1, "size": 20}
query = {**params, "timestamp": (ts := int(time.time() * 1000)), "sign": make_sign(params, ts, "SALT_FROM_JS")}
先验证再深入:把复刻值与浏览器真实值放一起比对,是整个流程的迭代锚点;很多「逆向很难」的印象来自不复刻比对、凭感觉瞎试。
实例或案例
某公开数据接口的 sign 经定位仅为 md5(page + "v1_public"),十分钟完成还原——遇到加密参数先假设它简单,验证失败再升级复杂度假设。真正困难的混淆(企业级风控、设备指纹绑定)通常伴随强法律边界,正确选项是放弃接口路线、回到授权渠道或浏览器方案,而不是硬刚。
常见误区
- 误区一:见到加密参数就宣布「不能爬」。 先搜索定位,多数站点的签名可读可复刻。
- 误区二:硬啃混淆代码。 目标是拿到参数值而非读懂每一行;抠函数交给 Node 执行是合法且高效的捷径。
- 误区三:把「能破解」当成「可以爬」。 技术可行 ≠ 授权允许;绕过访问控制获取非公开数据在多数法域违法(见 kp-004)。
自测题
- 定位签名生成点的两个抓手?
答:Sources 全局搜索参数名;对目标接口打 XHR 断点,从调用栈回溯到生成函数。
- 复杂混淆下最务实的做法?
答:不逐行还原,抠出相关函数片段用 Node/PyExecJS 本地执行,黑盒产出参数值。
- 什么时候应当停止逆向?
答:涉及绕过访问控制/付费/风控的未授权目标,或签名与设备指纹强绑定的企业级风控——回到授权渠道或浏览器路线。
与其他知识点的关系
kp-013 是逆向失败后的兜底;kp-016 从防守视角解释为什么有签名;kp-034 的验证码属另一类门禁,思路同源。
延伸阅读
Chrome DevTools 官方文档「Debug JavaScript」(断点与调用栈);MDN 的 Web Crypto 概念页。