小程序下单接口有 X-Ca-Signature/X-Ca-Nonce/X-Ca-Timestamp,反编译找不到生成逻辑,求思路

1 天前
 fire2y
最近一直在和喜欢的妹子打羽毛球,每次周末抢不到体育馆场地,想写脚本来抢。
我用 wxapkg 把本地小程序解包,看到了反编译代码;用 Charles 抓包发现下单接口请求头有 X-Ca-Signature 、X-Ca-Nonce 、X-Ca-Timestamp ,如果这几个头不对就会 401 。
问题是:在反编译的代码里找不到这几个请求头是怎么生成的,Charles 里也没有看到其他接口会返回这三个值(也没找到生成签名的接口)。我尝试用 Claude 分析,它只做了关键字匹配,判断这是阿里的接口,但仍在 Charles 里找不到相关请求。
大家有什么思路?是我没完全解密前端,还是小程序有特殊机制在生成这几个头?
731 次点击
所在节点    程序员
17 条回复
Vegetable
1 天前
时间戳、Nonce 、Signature 这三个字段是常见的签名字段。正常来说,前端会有一段逻辑,根据该请求的业务请求参数、当前时间、随机生成的 Nonce 作为输入,来生成一个签名,并将这三个东西和其他请求参数一起发送给后端。

所以,如你所想,这三个参数是在前端生成的。时间戳就是时间戳,确保请求有一定时效性。Signature 就是签名结果,Nonce 是 Number used Once ,可以起到防重放作用(时间戳有效的窗口内,所有使用过的 Nonce 都记录下来)

这些参数通常不会和微信有什么关系,至少我没见过微信提供这些东西,都是前后端约定的。你可以终点在代码里搜索一些哈希操作 Crypto 库之类的,只有这些信息很难提出什么建设性意见。
fire2y
1 天前
@Vegetable 我在代码里面能找到有 Crypto 库之类库 我怀疑是这部分的代码完全被混淆了 在一个大的文件里面 有 1w 多行 我关键字搜索能搜索到 结论应该就是前端生成的 只是被混淆了 我还是有机会破解出来 如果是小程序的机制 我就直接放弃了
microBlock
1 天前
叫啥小程序,我可以帮你逆向看看
fire2y
1 天前
@microBlock 川沙体育中心 curl -H "Host: shop.chuanshatiyuchang.cn" -H "X-Ca-Signature: Cr6EfMOwHP3q4oGCXMPXfj2rxiWUR0usg0CBsmnJY+P8ZmDmqrhdnf/4HeNxVwiFpk8NtSHxfX5SJc0RS/dfjbm0Javmqev+3ADWMqOe65nYIyxib5csEphHCa/JgYlZXwkzXDLz0lf06LqjtfToVjk2hilOjPKKrQbgx8HsPF9MbhKBJtyrDNul4pvOxIfiGSSk8+CVfdXlWDXQJnOPiSa7tyUty9l6/q0FZqSXDB97UYQKOlbxUmksGA4A2HcZuVzYo5ivgwDW6ib57PywNtSHoVBefktP2BZmaYz57SHcBh+69X6mb6DWwq0B8sWIkOdrcWcbPRVOm1Qre6ChkQ==" -H "X-Ca-Nonce: icp62g" -H "X-Ca-Timestamp: 1758707658" -H "User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 MicroMessenger/6.8.0(0x16080000) NetType/WIFI MiniProgramEnv/Mac MacWechat/WMPF MacWechat/3.8.10(0x13080a10) XWEB/1227" -H "token-user: xxxxxxx" -H "x-gym-client-id: 1" -H "Content-Type: application/json" -H "xweb_xhr: 1" -H "Accept: */*" -H "Sec-Fetch-Site: cross-site" -H "Sec-Fetch-Mode: cors" -H "Sec-Fetch-Dest: empty" -H "Referer: https://servicewechat.com/wx2fdf924861911ddc/15/page-frame.html" -H "Accept-Language: zh-CN,zh;q=0.9" --data-binary "{\"venueSportId\":1,\"areaItems\":[{\"areaDate\":\"2025-09-25\",\"areaId\":43,\"areaName\":\"三号场(3F)\",\"endTime\":\"11:00\",\"packageId\":null,\"price\":\"35\",\"showStatus\":\"AVAILABLE\",\"sportId\":1,\"sportName\":\"羽毛球\",\"startTime\":\"10:00\",\"status\":\"NORMAL\",\"uniqNo\":\"43_20250925_10:00_11:00\",\"checked\":true,\"row\":2,\"col\":1},{\"areaDate\":\"2025-09-25\",\"areaId\":43,\"areaName\":\"三号场(3F)\",\"endTime\":\"12:00\",\"packageId\":null,\"price\":\"35\",\"showStatus\":\"AVAILABLE\",\"sportId\":1,\"sportName\":\"羽毛球\",\"startTime\":\"11:00\",\"status\":\"NORMAL\",\"uniqNo\":\"43_20250925_11:00_12:00\",\"checked\":true,\"row\":2,\"col\":2}]}" --compressed "https://shop.chuanshatiyuchang.cn/gym/miniprogram/areaOrder/createOrder" 这个是具体的那个接口
microBlock
1 天前
找到了
microBlock
1 天前
// 引入 jsrsasign 库
const jsrsasign = require('jsrsasign');


const RSA_SIGN_KEY = "-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDPi4B6DrHEMpDA
8t9VOCkB2/mKEeSwQxdKwTks9HuZiG0nMxJ4Uj1cRrBHjr+9GB8ZyUFeZE+muVnj
ql9OeymWNlgWcISpFu6S49gT56RnMlXQCTKFMfhXfFsXQ7GiioeUIq6HmLOtvuX5
StK7TwodAxzQQpjUx0XIHmRKk2XHgktZlD0B3LuvAO7Y73fkwR/Kp3vXTnJShiSt
XbHTdC7GSXCvqglfGN5jyigmHqwgC1di+QGILPLJEDXpoAYtmcWWzs182ALShde9
sBR0BV6+DWCyeVzBEIwQKo+azdqmsdQkD1mXZj33iuVNJ+WcEg/D8i4byx5uouDU
dFvbuMNZAgMBAAECggEABP9vfcD1KpaAd4esYBwk71IG7XpmfuYcB/qk2qkdLC0l
r8AiQuUmwXOZqBzPD4nRVJN3mwMgYJFDEbaXFUflpaPeYCqfzzCUWH4wbwjwzmQJ
vqOSD19iLb0lYRHfaQdxTLG/G9h4rzI9zdCC8uwW1WxZ7nFEG+TxOxNG8qgfrHuy
zkihcWYDmmmoLqMg5CBi8QBWfkohegox3vOjAbX3OKjnWUf7aSiuIlZrXy9mEgqd
zQhsDDHGje0MqpkS6o9Y362LI8CD69K03NyLRc5FnlzWD5R21w7hlOWAN+/WIQWl
7uVMI/B5lMbsJ8t6nrZk46bFVqSSiqdY6XHXNUJdGQKBgQDsXKgoigXcVXlcVvzD
CMn7UkVCjwXpBXLMS4VXheWLGP2hLxBSZeOXdJ4hknkn/zKFv1X6/3VoLnJnYMm6
yyerpsTRhUM+jwkOF4/EgM/pOBc9RVOmmLWAUFy0mdabnBvK2Rvt+qSyZepYvcc1
GGvPg2ssKXjBaAbx/xFpx6kTzQKBgQDgyeqVUKULrEU2KQ8JAbdT0+ht5mT2LDn+
W2HjuPlcHtNI1co9UUZ6byZXXoE4TZ1W0cAaTiHpw3o2hDql9YfZQ7NWdhwNO1sm
/eYcJa1R8xyKlKtVnCPlzOA/gVJmSv50e1WNvzUsTwLHwoHZVX9UjGPqw5d2pVpj
ViuNTO65vQKBgQDWxBZzx34tx2ifs9a17N2CxC10nfpz0mSOJy0A6wQ40Ltc4yPE
ixoyu18YCDyYUDT6/HFGwSpQQKvpLTP/y6q/OKhr7Ne+Fz/WEyiqF5VTR4kuPjkV
DnsVHXAvFf2/pShHt+C961oNU7eNbNt+bjM/+hy+ouw7aKeu6eJLqIUEHQKBgGST
k4VJdv9ZDgKkrlh+TxOPzgBWRLgso6oeIxdr7Q59sFV3aqyyz9D6KHKRE0oo2Aw/
fy+F5ACe+PCpi0A0MptQgk5ePEDjXO5+TdYsOXdgSlXrHRoJ6bnpSDDB4SdpyJ4/
jNEGS3lOxNSyP70JVxZyVkZ1SzDH3UBzDruDP5EVAoGAGl5IhadThpODVbV+0s51
V8ZRHgzYAHZv4CdPCqugRP+vMIzoQEaiMMODY8JUzH2wi/qJWwHB7nqeCBS63I1O
HJjRE8D9qSbhiuR2L3E3mgK6TWGPKQQqAz3NUwml0gQSZAZqhLj9lDQtBJlWkG7A
kNPV6fWKE6QCp2JR/kAJU6E=
-----END PRIVATE KEY-----";


const generateRandomString = function() {
for (var t = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : 6,
r = arguments.length > 1 && void 0 !== arguments[1] ? arguments[1] : 8,
e = "abcdefghijklmnopqrstuvwxyz0123456789",
n = Math.floor(Math.random() * (r - t + 1)) + t,
o = "", a = 0; a < n; a++) {
var d = Math.floor(Math.random() * e.length);
o += e[d]
}
return "".concat(o)
};


function generateSignatureHeaders() {
// 生成当前时间戳(秒级)
const timestamp = Math.floor(Date.now() / 1000).toString();
// 生成随机字符串(使用默认长度范围 6-8 )
const nonce = generateRandomString();
// 待签名的字符串
const signatureStr = `${timestamp}\n${nonce}\nade2223c47623d82ecbc413fa5cc6dc1\n`;

// 初始化 RSA 密钥
const rsaKey = jsrsasign.KEYUTIL.getKey(RSA_SIGN_KEY);

// 初始化签名器
const signature = new jsrsasign.KJUR.crypto.Signature({
alg: "SHA256withRSA"
});

// 进行签名
signature.init(rsaKey);
signature.updateString(signatureStr);
const signedHex = signature.sign();
const signedBase64 = jsrsasign.hextob64(signedHex);

return {
"X-Ca-Timestamp": timestamp,
"X-Ca-Nonce": nonce,
"X-Ca-Signature": signedBase64
};
}
v1
1 天前
单就这个帖子,都能当作呈堂证供了……你们交流好歹用截图,图床至少随时能删
root71370
1 天前
666 学到了
python35
1 天前
六百六十六 还是 V 友神人多 只要不是实名上网问题不大
Monad
1 天前
@microBlock #6 大佬有没有可能授人以渔
microBlock
20 小时 29 分钟前
@Monad 面向监狱编程
fire2y
20 小时 4 分钟前
@microBlock 大佬太🐮了 我是真没找到函数是哪里变出来的
microBlock
20 小时 2 分钟前
@fire2y 我用 ai 写的
microBlock
20 小时 2 分钟前
@fire2y 你先试试能不能正常用 我没测试
fire2y
19 小时 40 分钟前
@microBlock 成了 一把过 🐮逼
JimLee0921
19 小时 37 分钟前
为什么好像之前看到过这个羽毛球馆预约帖子???
shen13176101
14 小时 37 分钟前
@JimLee0921 #16 之前我发过一个羽毛球的帖子,每次定场地 需要发送验证码 这样 一个手机只能抢一个场地,问有没有好办法处理,接口没有加密字段,但是服务器会判断是否是脚本,会封号。最后 不搞了。后来听说八点抢场地,七点五十八就有人可以提前发送验证码,当时我觉得很奇怪,发送验证码的接口明明有时间校验。搞不懂。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1161546

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX