抽奖助手小程序研究

抽奖助手小程序研究

一个只允许内部抽奖的请求如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
POST /v2/lottery/8zKwAa7L1Ff/join HTTP/2
Host: lucky.nocode.com
Content-Length: 483
Version: 2.6.17
Client-Version: 3.9.10
Sdkversion: 3.4.3
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjo0OTk4ODc1NiwiaWF0IjoxNzE2MTcxODkzLCJleHAiOjE3MTY3NzY2OTN9.Bnc6Kge43eqbUiPrJ4JB3Fbou_W60-cgyk_6lZhT-io
Content-Type: application/json
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 MicroMessenger/7.0.20.1781(0x6700143B) NetType/WIFI MiniProgramEnv/Windows WindowsWechat/WMPF WindowsWechat(0x63090a13) XWEB/9129
Timestamp: 1716256693801
Xweb_xhr: 1
Platform: wechat
Sign: f9736e8cbbf45eab3bd3bf4a27a5f36ebdf19a9a
X-Request-Id: 95476190-1715-11ef-b771-3bf552015d6c
Accept: */*
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://servicewechat.com/wx01bb1ef166cd3f4e/2121/page-frame.html
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9

{"form_id":"","source":{"type":"groupchat","data":"{\"encryptedData\":\"NEgbNTbr0CaM+KLYz33+r684aJQBIz9KPFMsMysFeKt8k+M4RNX8Y3Q69LFbUwVNV2WdyiowzIsgytwFJKSUM8se9LaX/JkdU5ch5hzf8evszJq7FnpkvBZteWLy0H03Nye1/xs5VFOyeEaInFcrBw==\",\"iv\":\"LVE6y+fy50i0R3tPEiuffw==\"}"},"direct_share_info":{"encryptedData":"Pgr8C/iW0s2TJTSRY8y/E6KJsQZzGm6n3539Uk4fK52AlDS/z5K8gRxjBU52Wdt8fir6tMLYgaGlgzjOiB+/aNjZuH/QvYPWM1AZD3TH+NLLWhT7CgavNBUwOXe+L53/","iv":"ljRdbV7izYorDqml1CgAGQ=="},"location":null}

数据开起来加密了,实际上可以忽略,因为POST中的数据是小程序API返回的。

source的数据来自wx.getShareInfo()

direct_share_info的数据来自wx.authPrivateMessage()

实例数据:

1
2
3
4
{"errMsg":"getShareInfo:ok","errno":0,"errorCode":0,"encryptedData":"0/flEF4dUxS/FtUHLthO/j+SJFgFjrc7xpYV0oM2LL1k5517/6GYFW2NBjLz20Pai4ahc/7a8BQ3qStz8bl6Ektc3C8Do/Bk6ANcRJzdT0Jg9e0lDr4UFBVfpDTYvWxokJXaDuwPndOCh0RUhNCCgg==","iv":"d17cSep9K4HqPlMBCuz2Ng==","cloudID":"80_FzgitqrYtDns7ciKxjhnZ4kGaZSf3j0a_Qh_ih5APlSvou8kf3h_DJCSKNU"}


{"iv":"fK+HbsG4G80QEsfuDMtZMg==","encryptedData":"xHUp9e2SDGoVI1NfcEyM0qHT+GrW+hjT/iV5U3tc4yHGfwGBB64ALG2KMHNEDxEFQumFnVsG6H9/7ReOzOnRgSAzN3mpREUZVRBhbTyv5vU=","valid":true,"errMsg":"authPrivateMessage:ok"}

getShareInfo的数据可以随意填充,服务器不会进行校验。

当开启“群成员参与”时,服务器会严格校验authPrivateMessage返回的内容。

image-20240521161414466

对于限制了参与人数、且仅允许群内成员参与的抽奖活动,可以提前进入群内之前的抽奖小程序链接,调用wx.authPrivateMessagewx.getShareInfo获取必要参数。

调用这两个接口都需要shareTicket。 至于shareTicket如何生成,我并没有找到答案。我猜测是随机生成,然后通过一些微信接口将生成的值与当前微信账号绑定,因为在断网的情况下,依然可以获取到shareTicket

image-20240521163152226

1
2
3
4
5

wx.authPrivateMessage({shareTicket: '38538646-26e4-4e9e-a936-3481196a35ab',success: function(e) {console.log(JSON.stringify(e))}})

wx.getShareInfo({shareTicket: '38538646-26e4-4e9e-a936-3481196a35ab',timeout: 2e3,success: function(e) {console.log(JSON.stringify(e))}})

image-20240521163916219

签名

签名流程:

  1. 将POST请求中的json转成query格式的字符串(key升序)

  2. 计算上一步字字符串的md5

  3. 拼接字符串: 请求方法url 、上一步的md5、时间戳、密钥

    1
    post:/lottery/8zLwZp27ojC/join::d33f07a0efe04c68feb2d4aee04a2ea9:1716279736660:nuTW7z+c(H?MD+kbWR6XGnb6Be2v8ttU:1
  4. 计算sha1

json转query字符串的过程中存在BUG,比如前面的那个请求,转成的字符串为:

1
direct_share_info=object&form_id=&location=&source=object

direct_share_infosource的值被强制转成了字符串”object”,导致修改这两个参数后签名不会变。

参考资料

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/share/private-message.html

https://zhuanlan.zhihu.com/p/36045620