没有官方人员回答一下吗?
【紧急】小程序支付功能被封禁,未告知具体违规原因?微信小程序接入的B2B支付,昨天还能支付,今天提示“支付失败”,还有个图层提示的是“由于小程序违规,支付功能暂时无法使用”。 控制台errno:102 没有收到任何系统通知 APPID:wx8e8a6caa2c7f3150 麻烦告知具体违规原因!
06-18帮了大忙了兄弟,顺便贴一下PHP版的。 protected function decryptMessage($postData, $timestamp, $nonce, $msgSignature) { $config = config('wechat'); // 签名验证 $array = [$postData, $config['payment']['token'], $timestamp, $nonce]; sort($array, SORT_STRING); $str = implode($array); $sign = sha1($str); if ($sign !== $msgSignature) { throw new Exception('加密数据签名验证失败'); } try { // AES 密钥解码 $aesKey = base64_decode($config['payment']['aes_key']); if (strlen($aesKey) !== 32) { throw new Exception('AES 密钥长度不正确'); } $iv = substr($aesKey, 0, 16); $base64Decode = base64_decode($postData); // 解密数据 $data = openssl_decrypt($base64Decode, 'aes-256-cbc', $aesKey, OPENSSL_RAW_DATA | OPENSSL_NO_PADDING, $iv); // 去除头部信息 $filterHeader = substr($data, 20); // 替换 app_id $appId = preg_quote($config['mini_program']['app_id'], '/'); $content = preg_replace('/' . $appId . '/', '', $filterHeader); // 返回解密后的数据 return json_decode($content, true); } catch (\Throwable $e) { Log::error('Decrypt failed: ' . $e->getMessage()); throw new Exception('解密数据失败'); } }
小程序消息推送解密文档过时(附正确代码)https://developers.weixin.qq.com/miniprogram/dev/framework/server-ability/message-push.html 这篇文章里提到的AES加密策略为 AES/CBC/PKCS7Padding,实测无法解密。下载文中提供的SDK,其中的策略为 AES/CBC/NoPadding,实测可以成功解密。另外原文缺少对iv参数的描述,希望完善。 附针对当前文档提供的示例明文、密文,可得出正确结果的Java解密代码: import cn.hutool.core.codec.Base64; import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.ArrayUtil; import cn.hutool.crypto.symmetric.AES; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.*; import javax.crypto.spec.IvParameterSpec; import java.util.Arrays; import java.util.Map; /** * 接收消息推送,解密方式为安全模式 */ @PostMapping public static String receive(@RequestParam("signature") String signature, @RequestParam("timestamp") String timestamp, @RequestParam("nonce") String nonce, @RequestParam("openid") String openid, @RequestParam("encrypt_type") String encryptType, @RequestParam("msg_signature") String msgSignature, @RequestBody Map requestBody) { log.info("收到微信小程序消息推送:signature={}, timestamp={}, nonce={}, openid={}, encrypt_type={}, msg_signature={}, requestBody={}", signature, timestamp, nonce, openid, encryptType, msgSignature, requestBody); /* 请求报文体示例: { "ToUserName": "gh_97417a04a28d", "Encrypt": "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04=" } */ String encrypt = MapUtil.getStr(requestBody, "Encrypt"); // 验签 // 将三个值按字典值排序拼接 String token = "AAAAA"; String[] strings = {token, timestamp, nonce, encrypt}; Arrays.sort(strings); String textToSign = ArrayUtil.join(strings, ""); // 验签 boolean verify = DigestUtils.sha1Hex(textToSign).equals(msgSignature); log.info("验签结果:{}", verify); if (!verify) { return null; } // 解密消息 String encodingAesKey = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; byte[] aesKey = Base64.decode(encodingAesKey + "="); byte[] tmpMsg = Base64.decode(encrypt); IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16)); AES aes = new AES("CBC", "NoPadding", aesKey, iv.getIV()); // fullStr结构:random(16B) + msg_len(4B) + msg + appid,其中 // random(16B)为 16 字节的随机字符串; final int randomPartSize = 16; // msg_len 为 msg 长度,占 4 个字节(网络字节序); final int msgLenPartSize = 4; // msg为明文; // appid为小程序Appid。 byte[] fullStr = trimPadding(aes.decrypt(tmpMsg)); // 删除明文补位字符 String random = new String(Arrays.copyOfRange(fullStr, 0, randomPartSize)); int msgLen = ByteBuffer.wrap(Arrays.copyOfRange(fullStr, randomPartSize, randomPartSize + msgLenPartSize)).getInt(); String msg = new String(Arrays.copyOfRange(fullStr, randomPartSize + msgLenPartSize, randomPartSize + msgLenPartSize + msgLen));; String appid = new String(Arrays.copyOfRange(fullStr, randomPartSize + msgLenPartSize + msgLen, fullStr.length));; log.info("解密结果:random={}, msg_len={}, msg={}, appid={}", random, msgLen, msg, appid); // 如无特殊要求一般返回空或success,其他内容则需要加密返回 return "success"; } /** * 删除解密后明文的补位字符 * * @param decrypted 解密后的明文 * @return 删除补位字符后的明文 */ private static byte[] trimPadding(byte[] decrypted) { int pad = decrypted[decrypted.length - 1]; if (pad < 1 || pad > 32) { pad = 0; } return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad); } public static void main(String[] args) { String signature = "6c5c811b55cc85e0e1b54100749188c20beb3f5d"; String timestamp = "1714112445"; String nonce = "415670741"; String openid = "o9AgO5Kd5ggOC-bXrbNODIiE3bGY"; String encryptType = "aes"; String msgSignature = "046e02f8204d34f8ba5fa3b1db94908f3df2e9b3"; Map requestBody = MapUtil.newHashMap(); requestBody.put("ToUserName", "gh_97417a04a28d"); requestBody.put("Encrypt", "+qdx1OKCy+5JPCBFWw70tm0fJGb2Jmeia4FCB7kao+/Q5c/ohsOzQHi8khUOb05JCpj0JB4RvQMkUyus8TPxLKJGQqcvZqzDpVzazhZv6JsXUnnR8XGT740XgXZUXQ7vJVnAG+tE8NUd4yFyjPy7GgiaviNrlCTj+l5kdfMuFUPpRSrfMZuMcp3Fn2Pede2IuQrKEYwKSqFIZoNqJ4M8EajAsjLY2km32IIjdf8YL/P50F7mStwntrA2cPDrM1kb6mOcfBgRtWygb3VIYnSeOBrebufAlr7F9mFUPAJGj04="); System.out.println(receive(signature, timestamp, nonce, openid, encryptType, msgSignature, requestBody)); }
04-26能给个在线的技术人员吗?咋不跟支付宝学学呢? 17,18号的通知就可以解密,21,22号的就不行了,这什么鬼?
b2b支付通知消息推送解密问题,第一次解密成功,后续解密失败。使用的是b2b支付中的面向普通用户的小程序支付,第一次拿到支付通知消息解密正常。再下单收到的通知就解密不了。 可以确定的是aes key和token之类的参数肯定没有变化。我不知道怎么确定问题了。需要提供什么信息我发一下。
04-22