V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
fire2y
V2EX  ›  程序员

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

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

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

    这些参数通常不会和微信有什么关系,至少我没见过微信提供这些东西,都是前后端约定的。你可以终点在代码里搜索一些哈希操作 Crypto 库之类的,只有这些信息很难提出什么建设性意见。
    fire2y
        2
    fire2y  
    OP
       1 天前
    @Vegetable 我在代码里面能找到有 Crypto 库之类库 我怀疑是这部分的代码完全被混淆了 在一个大的文件里面 有 1w 多行 我关键字搜索能搜索到 结论应该就是前端生成的 只是被混淆了 我还是有机会破解出来 如果是小程序的机制 我就直接放弃了
    microBlock
        3
    microBlock  
       1 天前
    叫啥小程序,我可以帮你逆向看看
    fire2y
        4
    fire2y  
    OP
       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
        5
    microBlock  
       23 小时 24 分钟前   ❤️ 1
    找到了
    microBlock
        6
    microBlock  
       23 小时 16 分钟前   ❤️ 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
        7
    v1  
       22 小时 25 分钟前   ❤️ 1
    单就这个帖子,都能当作呈堂证供了……你们交流好歹用截图,图床至少随时能删
    root71370
        8
    root71370  
       22 小时 0 分钟前 via Android
    666 学到了
    python35
        9
    python35  
       21 小时 44 分钟前
    六百六十六 还是 V 友神人多 只要不是实名上网问题不大
    Monad
        10
    Monad  
       21 小时 32 分钟前
    @microBlock #6 大佬有没有可能授人以渔
    microBlock
        11
    microBlock  
       9 小时 4 分钟前   ❤️ 1
    @Monad 面向监狱编程
    fire2y
        12
    fire2y  
    OP
       8 小时 39 分钟前
    @microBlock 大佬太🐮了 我是真没找到函数是哪里变出来的
    microBlock
        13
    microBlock  
       8 小时 37 分钟前
    @fire2y 我用 ai 写的
    microBlock
        14
    microBlock  
       8 小时 37 分钟前
    @fire2y 你先试试能不能正常用 我没测试
    fire2y
        15
    fire2y  
    OP
       8 小时 16 分钟前
    @microBlock 成了 一把过 🐮逼
    JimLee0921
        16
    JimLee0921  
       8 小时 13 分钟前
    为什么好像之前看到过这个羽毛球馆预约帖子???
    shen13176101
        17
    shen13176101  
       3 小时 12 分钟前
    @JimLee0921 #16 之前我发过一个羽毛球的帖子,每次定场地 需要发送验证码 这样 一个手机只能抢一个场地,问有没有好办法处理,接口没有加密字段,但是服务器会判断是否是脚本,会封号。最后 不搞了。后来听说八点抢场地,七点五十八就有人可以提前发送验证码,当时我觉得很奇怪,发送验证码的接口明明有时间校验。搞不懂。
    关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3095 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 11:45 · PVG 19:45 · LAX 04:45 · JFK 07:45
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.