- 小程序、公众号、第三方平台等场景下,微信服务器推送的消息如何解密|NodeJS
本篇是对微信官方文档进行补充,一般需要消息解密的场景主要有如下几种: 第三方平台的消息推送:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/2.0/api/Before_Develop/message_push.html网站应用的消息推送:https://developers.weixin.qq.com/doc/oplatform/Website_App/WeChat_Login/message_push.html移动应用的消息推送:https://developers.weixin.qq.com/doc/oplatform/Mobile_App/WeChat_Login/message_push.html公众号接收用户消息:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_standard_messages.html公众号接收事件推送:https://developers.weixin.qq.com/doc/offiaccount/Message_Management/Receiving_event_pushes.html小程序接收用户消息和事件:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/customer-message/receive.html你需要按照各自指引文档,开放你的服务器 http 服务,通过在管理后台配置你服务器的指定路径和加密参数,来和微信服务确定消息的沟通事宜。 [图片] 一般涉及到加密消息的只有 Token 和 EncodeingAESKey 两个,只需要保证你的服务器加解密的信息和微信服务的一致即可,所以这个你可以指定。 指定加密信息和服务器路径之后,微信服务器会按照你的加密信息对原始数据进行加密,然后向你指定的 http 服务路径中发送 post 请求。 当你的服务器收到微信服务器发来的请求时,你应该能得到直接拼在请求路径里的 query 参数 比如你的路径为:https://www.example.com/wxmp/ 那么实际收到的应该是: https://www.example.com/wxmp/?signature=f464b24fc39322e44b38aa78f5edd27bd1441696&echostr=4375120948345356249×tamp=1714036504&nonce=1514711492 你可以将 query 参数拿出来,以备后面解密使用。 另外在请求的 body 中,是一个 base64 编码数据(如果你选择的明文模式,收到的可能是明文) 你需要先解析一下这个 base64 数据,得到一个 xml 或者 json 类型的明文数据,里面有两个东西: Appid,这个消息应该所属的应用id(小程序、公众号、第三方平台、移动应用、网站应用、企业微信等)Encrypt,真正的消息体(加密过的,我们后面需要解密)接下来我们就对比 Appid 是否是我们的应用,如果是则继续处理消息体;如果不是就直接丢掉。 处理消息体前,我们需要先验证一下真实性,对 Encrypt 内容进行签名(需要用到配置的 Token,以及 query 里的 timestamp、nonce ),看下是否和 query 参数里提供的 signature (前面如果有加密的话,这里应该是 msg_signature)相同,不同则证明被篡改或者解密信息对应,也没必要继续解了。 如果签名一致,我们就可以继续解密 Encrypt 内容。 解密需要用到一开始配置的 EncodeingAESKey ,AES 使用 CBC 模式,具体的可以直接参考代码: 代码包下载:https://wximg.gtimg.com/shake_tv/mpwiki/cryptoDemo.zip 上面链接代码包里没有 NodeJS,考虑到相当部分的开发者都用 NodeJS 来开发服务端,所以这里提供最小代码,方便参照设计自己的解密模块。 代码可以直接复制下来运行,需要额外安装 xml2js 模块,最后部分为测试实例(里面的 token 和 key 信息都脱敏过,不需要担心) const crypto = require('crypto') const xml2js = require('xml2js') const xmlparser = new xml2js.Parser() const ALGORITHM = 'aes-256-cbc' // 使用的加密算法 const MSG_LENGTH_SIZE = 4 // 存放消息体尺寸的空间大小。单位:字节 const RANDOM_BYTES_SIZE = 16 // 随机数据的大小。单位:字节 /** * 解密数据 * @param {*} encryptdMsg 加密消息体 * @param {*} encodingAESKey AES 加密密钥 * @returns */ function decode (encryptdMsg, encodingAESKey) { const key = Buffer.from(encodingAESKey + '=', 'base64') // 解码密钥 const iv = key.subarray(0, 16) // 初始化向量为密钥的前16字节 const encryptedMsgBuf = Buffer.from(encryptdMsg, 'base64') // 将 base64 编码的数据转成 buffer const decipher = crypto.createDecipheriv(ALGORITHM, key, iv) // 创建解密器实例 decipher.setAutoPadding(false) // 禁用默认的数据填充方式 let decryptdBuf = Buffer.concat([decipher.update(encryptedMsgBuf), decipher.final()]) // 解密后的数据 const padSize = decryptdBuf[decryptdBuf.length - 1] decryptdBuf = decryptdBuf.subarray(0, decryptdBuf.length - padSize) // 去除填充的数据 const msgSize = decryptdBuf.readUInt32BE(RANDOM_BYTES_SIZE) // 根据指定偏移值,从 buffer 中读取消息体的大小,单位:字节 const msgBufStartPos = RANDOM_BYTES_SIZE + MSG_LENGTH_SIZE // 消息体的起始位置 const msgBufEndPos = msgBufStartPos + msgSize // 消息体的结束位置 const msgBuf = decryptdBuf.subarray(msgBufStartPos, msgBufEndPos) // 从 buffer 中提取消息体 return msgBuf.toString() // 将消息体转成字符串,并返回数据 } /** * 生成签名 * @param {*} encrypt 加密消息体 * @param {*} timestamp 时间戳 * @param {*} nonce 随机数 * @param {*} token 令牌 * @returns */ function genSign (encrypt, timestamp, nonce, token) { const rawStr = [token, timestamp, nonce, encrypt].sort().join('') // 原始字符串 const signature = crypto.createHash('sha1').update(rawStr).digest('hex') // 计算签名 return signature } // --------------------------- 以下为测试代码 --------------------------- // 与微信后台的 encodingAESKey 保持一致 const encodingAESKey = "KE66t5p56ig2rz66Ep2H6bTiitgP2ib26GbuT9tumBB" // 与微信后台的 token 保持一致 const token = "fjKCjCksHwYwHZWARPgtjKKYZyRAstkr" // 你的服务器会收到微信服务器发送的消息,这是 query 参数 const query = { signature: 'eab668051feb6330f0f84e9a9b0bc8d9d972c049', // 有些平台会对加密消息体再做一层 base64,这里就是此 base64 的签名,否则就是真的加密消息体的签名 timestamp: '1721800206', // 签名要用 nonce: '1727131331', // 签名要用 encrypt_type: 'aes', // 有些平台会有特殊加解密方式,请参考实际文档,默认 aes_cbc msg_signature: '31c02ec801f178b72e712427a64a59be01ebec5a' // 有些平台会对加密消息体再做一层 base64,所以这里有提供就是真的加密消息体的签名 } // 你的服务器会收到微信服务器发送的消息,这是 body 参数,绝大部分会是 xml 消息体,有时会做一层 base64 编码 // 需要先 base64 解码,然后得到 xml 解析,xml 中会包含 Appid 和 Encrypt 两个,你需要验证 Appid 是你自己的,并且只取 Encrypt 中的内容就好,下面是内容。 const body = 'Sk+nxj+6bfJYOu1zmckuQhxVPaT9IRHA3C4wmNAJvYa7oBmxBg6nETY8dv7nWw9O8N2VbJYcANjBfDeGXOySKweRlEUHbDEzsHprI3A1WY6H73v4lg97TPyTudYVNDvY6ve4hEwlkxgx8WOl7Jd9HbpuIZJ4711CQuJQNuQyONkBFBXxQXuyIurthDv9/pxKYwnmV/NZQF6LKyuezAfjyoz35lqK7QgnfCW6kAB5wAiYOaW0CK4/4b9jo9J40jPumvs4d9Wa+t4Xzh1a8R6ogCTlw6EQSKGqEbKblSI8p0Dc2QDzEuRO+1qlcnoHmaacf14aL41Y148n6lObt9YPsTWI4CZNA0C4P7mPVsWd1v63vHTk4shI6VanpTruIjhdAEiWbeg+rFU5CQj5+0V0QJpQOQasFW9T4VW2m8s85isB9f4A91Q3+6bAoWlHBqj6c8tAnQzxtjMAJZDX2SNCov+B3kICZke2FLE+OhUVNxnsaETJ++EFUTwE7kOzgSGRen9Shnsi3CHEHSDLtveUavzfS33RWQzRSTGsZc++0ZNKrI1pgVR4Oew4WQgHGDxlRiVPeNvPFMD36V72ZE/0BSLdW3It/9TK34rLTx6xv7952VJ/gYKbTq0LBvvrt6YaFMJdPsnZlix8TUfNXRZN/MNsNJPOj4B+PgkU5duxbYc0bHvcA7oUlWnm3vSpIHaGBBsrsRaMAXLqluky9zM0l4fcS93Cyjcgt/eS7QkZWVpLKrtBkj2OmN0plBJNv8MiRcM/GX0BcHSBlyXeXbO/4vkkTRgKGbjLAWRBff8iP9j0RziTyVZ/i08QO79k0dXPrY/SON4wtVagHdU2FZ8pQA==' // 你需要自己计算一下消息的签名,并和微信服务器计算出来的签名进行比较。 const signature = genSign(body, query.timestamp, query.nonce, token) console.log('本地计算的签名:', signature) console.log('微信服务器计算的签名:', query.msg_signature) // 如果相同,说明消息是微信服务器发来的,否则说明消息不是微信服务器发来的 if(signature === query.msg_signature){ const result = decode(body, encodingAESKey) console.log('解密后的数据', result) // 如果是 XML 格式,可能比较难处理,所以下一步转换为 JSON,如果指定微信服务器发送JSON格式,可以忽略 xmlparser.parseStringPromise(result).then(res=>console.log('最终数据', res.xml)) } else { console.log('签名不一致') }
07-25 - 营业执照已经下来好久了,现在还还不能申请小程序,显示企业法定代表人姓名不一致”,法定代表人验证失败?
[图片][图片]已经一个月了,麻烦看一下
03-12 - 微信公众号部分相关客服(可转人工)
微信公众平台-小程序代码审核咨询微信公众平台-监管相关咨询微信公众平台-名称审核咨询公众号帐号审核-高危open官网咨询客服小程序交易组件第三方代创建小程序咨询MP客服消息规则调整反馈入口公众号作者小程序注册公众号客服消息调整视频号直播官方客服微信公众平台微信公众平台客服公众号账号审核-低质公众号账号审核-诱导公众号申诉咨询微信公众平台-公众号业务咨询发货信息管理客服小程序订单中心页Path设置审核订单发货管理客服小程序客服咨询模板消息问题咨询小程序隐私保护咨询付费管理-客服咨询模板消息枚举值审核咨询公众号营销内容咨询微信公众平台-小程序类目审核咨询小程序备案-客服咨询小程序年费咨询服务商采购-客服咨询公众号
2023-11-02 - 接收授权和人脸识别状态变更通知看起来真香,是否已风波过去?no(小程序快速注册踩坑三)【请关注此帖子,后期更新解决方案】
【问题0】: 已设置小程序名字和头像,简介,类目,提交代码审核,提示请设置名称和类目? 猜想:资料在审核。 等结果更新 【问题1】:接收授权和人脸识别状态变更通知收不到? 等待结果和更新 【问题2】:快注注册的小程序竟然是未认证? 等待结果和更新 【问题3】:客户都用资料人脸识别通过,并绑定完邮箱登录后台,收到的确是“法人姓名与主体不一致”? 等待结果和更新 【问题4】:人脸识别,法人口头表达的数字是正确的,但是却不能通过? 答案:小程序客户人脸认证的时候,注意要把电话挂断才可以,要不会认证失败。客户报那串数字时,如果麦克风被占用,即使报的对也没用。 [图片] 【问题5】:主体一致,却不能和同主体公众号用一个名字作为小程序名字? 客服:上一个因为主体括号不一致的情况,我这边找业务同学确认了一下,需要先使用其他昵称通过审核,然后去设置里面修正小程序的主体名称里面的括号为英文括号,才支持设置和公众号一样的名称哦 总结:也就是如果营业执照上有括号要格外的注意。 [图片][图片] 附件一些关于快速注册关键入口链接: 快速授权事件接收开发文档(notify_third_fasteregister和authorized是同一个地方处理,且开发文档未提及):https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/api/authorize_event.html快速注册开发文档:https://developers.weixin.qq.com/doc/oplatform/Third-party_Platforms/Mini_Programs/Fast_Registration_Interface_document.html小程序助手使用说明: https://developers.weixin.qq.com/miniprogram/analysis/assistant/国家企业信用信息公示系统: http://www.gsxt.gov.cn/index.html小程序助手”小程序设置登录邮箱和密码,设置完成后即可前往微信公众平台登录使用,具体可参考指引: https://kf.qq.com/touch/sappfaq/200617VbQzaa200617aq67ru.html无字号 个体户无字号无法提交资料怎么解决?、https://developers.weixin.qq.com/community/develop/doc/0008846eca4098b423da2d6ae56c00?highLine=%25E6%2597%25A0%25E5%25AD%2597%25E5%258F%25B7小程序取名建议:https://developers.weixin.qq.com/community/operate/doc/00060288824708b8d588e4ae25bc01 带地域的小程序名称审核不通过?https://developers.weixin.qq.com/community/develop/doc/000c2024c0cbc071fc99d094451c09?highLine=%25E6%2597%25A0%25E5%25AD%2597%25E5%258F%25B7
2020-12-14 - 第三方代注册小程序支持快速设置登录邮箱和密码
近期平台对第三方服务商代注册小程序的流程进行了优化,用户通过第三方服务商成功创建小程序后,将收到设置小程序登录邮箱和密码的微信消息提醒。管理员可通过点击提醒内的“前往设置邮箱密码”或直接搜索「小程序助手」小程序进行邮箱密码的设置。 温馨提示:所设置的邮箱需要是未绑定任何个人微信、公众号、小程序、微信开放平台的邮箱 详细操作流程如下: 1.打开“小程序助手”小程序,选择对应的小程序 [图片] 2.点击“登录邮箱”设置项 [图片] 3.填写邮箱以及设置小程序密码 [图片] 4.系统会发送验证邮件到邮箱 [图片][图片] 5.打开邮件中的链接,确认验证 [图片] 6.邮箱设置成功,可以在官网:mp.weixin.qq.com用所设置的邮箱和密码登录小程序后台 [图片] 如有疑惑,可微信搜索小程序服务商助手-我的-咨询反馈。
2020-07-03