2023-04-26-微信安全模式下消息解析

安全,模式,消息,解析 · 浏览次数 : 21

小编点评

## Go语言解密微信加密请求 以下是使用 Go 语言实现微信加密请求解密的示例代码: ```go import ( "encoding/hex" "crypto/aes" "crypto/sha1" "fmt" "io/ioutil" "os" ) func handlerEncrypt(body []byte, timestamp, nonce, msg_sig string) ([]byte, error) { // 创建加密请求结构 request := &WeChatEncryptRequest{} // Unmarshal 请求体 terr := xml.Unmarshal(body, request) if terr != nil { log.Errorf("unmarshal wechat encrypt request error: %s", terr.Error()) return nil, terr } // 验证消息签名 if calcSignature(token, timestamp, nonce, request.Encrypt) != msg_sig { log.Errorf("encrypt msg got from wechat verify signature failed") return nil, errors.New("encrypt msg got from wechat verify signature failed") } // 解密密文 cipherText, err := base64.StdEncoding.DecodeString(request.Encrypt) if err != nil { log.Errorf("decode wechat encrypt request error: %s", err.Error()) return nil, err } // 解密密文 block, err := aes.NewCipher(key) if err != nil { log.Errorf("decrypt wechat encrypt request error: %s", err.Error()) return nil, err } blockSize := block.BlockSize() blockMode := block.NewCBCDecrypter(block, key[:blockSize]) plainText := make([]byte, len(cipherText)) blockMode.CryptBlocks(plainText, cipherText) plainText = pkcs7UnPadding(plainText) // 返回解密后的密文 return plainText, nil } // 生成签名 func calcSignature(args ...string) string { sort.Strings(args) return hex.EncodeToString(sha1.New().Sum(args...)) } ``` **代码说明:** 1. 该代码首先创建一个 `WeChatEncryptRequest` 结构来存储加密请求信息。 2. 使用 `xml.Unmarshal` 解析请求体并将其赋值给 `request` 结构。 3. 验证消息签名,确保它与请求中的签名匹配。 4. 解密密文,使用 `aes.NewCipher` 和 `aes.NewCBCDecrypter` 类进行解密。 5. 使用 `pkcs7UnPadding` 函数对密文进行解码。 6. 最后,返回解密后的密文。 **注意:** 1. 密钥 `key` 要根据实际情况进行设置,例如从本地文件加载或获取从微信服务器获取。 2. 代码示例中的密钥长度为 16,建议根据实际情况进行调整。 3. 代码中使用了 `hex` 库对密文进行解码,您可以根据需要切换其他解码库。

正文

在微信公众号的使用过程中,为了提高信息传输的安全性,可以在服务器配置中将消息加解密模式指定为安全模式

启用安全模式后,公众号主动调用API的情况并不会受影响,只有被动回复用户的消息时才需要对消息进行加解密

官方提供了5种开发语言的示例代码,参照官方给的C++示例代码,本文给出go语言的解密实现:

func handlerEncrypt(body []byte, timestamp, nonce, msg_sig string) (random, rawXMLMsg []byte, err error) {
	request := &WeChatEncryptRequest{}
	err = xml.Unmarshal(body, request)
	if err != nil {
		log.Errorf("unmarshal wechat encrypt request error: %s")
		errors.Wrap(err, "unmarshal wechat encrypt request error")
		return
	}

	// verify msg from wechat signature
	if calcSignature(token, timestamp, nonce, request.Encrypt) != msg_sig {
		log.Errorf("encrypt msg got from wechat verify signature failed")
		errors.New("encrypt msg got from wechat verify signature failed")
		return
	}

	// decode cipher text from base64
	cipherText, err := base64.StdEncoding.DecodeString(request.Encrypt)
	if err != nil {
		log.Errorf("decode wechat encrypt request error: %s", err.Error())
		errors.Wrap(err, "decode wechat encrypt request error")
		return
	}
	// aes decrypt
	plainText, err := aesDecrypt(cipherText, key)
	if err != nil {
		log.Errorf("decrypt wechat encrypt request error: %s", err.Error())
		errors.Wrap(err, "decrypt wechat encrypt request error")
		return
	}

	// get raw wechat encrypt request length
	rawXMLMsgLen := int(ntohl(plainText[16:20]))
	if rawXMLMsgLen < 0 {
		log.Errorf("incorrect msg length: %d", rawXMLMsgLen)
		errors.Wrapf(err, "incorrect msg length: %d", rawXMLMsgLen)
		return
	}

	// verify appid
	appIDOffset := 20 + rawXMLMsgLen
	if len(plainText) <= appIDOffset {
		log.Errorf("msg length too large: %d", rawXMLMsgLen)
		errors.Wrapf(err, "msg length too large: %d", rawXMLMsgLen)
		return
	}
	// verify appid
	if appID != string(plainText[appIDOffset:]) {
		log.Errorf("Received an attack disguised as a WeChat server.")
		errors.New("Received an attack disguised as a WeChat server.")
		return
	}

	// get random which from wechat
	random = plainText[:16:20]

	// raw wechat msg
	rawXMLMsg = plainText[20:appIDOffset:appIDOffset]
	return
}

func calcSignature(args ...string) string {
	sort.Strings(args)
	h := sha1.New()
	for _, arg := range args {
		io.WriteString(h, arg)
	}

	return hex.EncodeToString(h.Sum(nil))
}

func aesDecrypt(cipherText []byte, key []byte) ([]byte, error) {
	block, err := aes.NewCipher(key)
	if err != nil {
		return nil, err
	}
	blockSize := block.BlockSize()
	blockMode := cipher.NewCBCDecrypter(block, key[:blockSize])
	plainText := make([]byte, len(cipherText))
	blockMode.CryptBlocks(plainText, cipherText)
	plainText = pkcs7UnPadding(plainText)
	return plainText, nil
}

func pkcs7UnPadding(data []byte) []byte {
	length := len(data)
	unpadding := int(data[length-1])
	return data[:(length - unpadding)]
}

func ntohl(orderBytes []byte) (n uint32) {
	return uint32(orderBytes[0])<<24 |
		uint32(orderBytes[1])<<16 |
		uint32(orderBytes[2])<<8 |
		uint32(orderBytes[3])
}

完整的代码示例在这里


声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。
Author: mengbin
blog: mengbin
Github: mengbin92
cnblogs: 恋水无意


与2023-04-26-微信安全模式下消息解析相似的内容:

2023-04-26-微信安全模式下消息解析

在微信公众号的使用过程中,为了提高信息传输的安全性,可以在服务器配置中将消息加解密模式指定为安全模式。 启用安全模式后,公众号主动调用API的情况并不会受影响,只有被动回复用户的消息时才需要对消息进行加解密。 官方提供了5种开发语言的示例代码,参照官方给的C++示例代码,本文给出go语言的解密实现:

LeetCode 周赛 342(2023/04/23)容斥原理、计数排序、滑动窗口、子数组 GCB

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 前天刚举办 2023 年力扣杯个人 SOLO 赛,昨天周赛就出了一场 Easy - Easy - Medium - Medium 的水场,不得不说 LeetCode 是懂礼数的 😁。 接

LeetCode 双周赛 103(2023/04/29)区间求和的树状数组经典应用

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 这场周赛是 LeetCode 双周赛第 103 场,难得在五一假期第一天打周赛的人数也没有少太多。这场比赛前 3 题比较简单,我们把篇幅留给最后一题。 往期周赛回顾:LeetCode 单周

LeetCode 周赛 343(2023/04/30)结合「下一个排列」的贪心构造问题

本文已收录到 AndroidFamily,技术和职场问题,请关注公众号 [彭旭锐] 提问。 大家好,我是小彭。 今天是五一假期的第二天,打周赛的人数比前一天的双周赛多了,难道大家都只玩一天吗?这场周赛是 LeetCode 第 343 场单周赛,如果不考虑第一题摆烂的翻译,整体题目质量还是很不错哒。

[转帖]数据库的可观测性能力与监控能力建设之间的差别

白鳝的洞穴2023-04-18 39 前阵子的DTC2023上,我分享的内容是关于数据库可观测性的。会后有不少朋友都和我聊了关于数据库可观测性的问题,也有很多朋友对于这个新名词感到有点高大上,不过并不以为然。认为可观测性就是以前的数据库监控的炒冷饭。实际上从数据库监控到利用数据库的可观测性能力去做数

[转帖]比较不同CPU下的分支预测

https://plantegg.github.io/2023/04/16/%E6%AF%94%E8%BE%83%E4%B8%8D%E5%90%8CCPU%E4%B8%8B%E7%9A%84%E5%88%86%E6%94%AF%E9%A2%84%E6%B5%8B/ 目的 本文通过一段对分支预测是否友

[转帖]比较不同CPU下的分支预测

https://plantegg.github.io/2023/04/16/%E6%AF%94%E8%BE%83%E4%B8%8D%E5%90%8CCPU%E4%B8%8B%E7%9A%84%E5%88%86%E6%94%AF%E9%A2%84%E6%B5%8B/ 所有 CPU 都期望对分支预测友好

.NET周报 【4月第4期 2023-04-23】

国内文章 2023成都.NET线下技术沙龙圆满结束 https://www.cnblogs.com/edisonchou/p/2023_chengdu_dotnet_club_activity_review.html 2023年4月15日周六,由MASA技术团队和成都.NET俱乐部共同主办的2023

.NET周报 【4月第1期 2023-04-02】

国内文章 探索 SK 示例 -- GitHub 存储库中的机器人 https://www.cnblogs.com/shanyou/p/17280627.html 微软 3月22日 一篇文章“Semantic-kernel 嵌入和记忆:使用聊天UI探索GitHub Repos”[1] ,文章中进行了展

.NET周报 【4月第2期 2023-04-08】

国内文章 LRU缓存替换策略及C#实现 https://www.cnblogs.com/eventhorizon/p/17290125.html 这篇文章讲述了缓存替换策略,特别是LRU算法。LRU算法基于这样一个假设:如果数据最近被访问过,那么将来被访问的几率也更高。通常我们会用双向链表来实现这个