2023-04-26-微信安全模式下消息解析
1.iota简介2.go generate命令简介3.golang uuid库介绍4.gRPC基本教程5.protolator简介6.Govulncheck v1.0.0 发布了!7.每日一库:GORM简介8.Go泛型简介9.Go 1.21发布!10.Golang zip压缩文件读写操作11.本地搭建playground12.zap自定义日志级别13.Gorm日志设置14.gin启动https支持15.Go Plugin介绍16.Golang漏洞管理17.可以丢掉123456了18.如何优雅地退出程序19.PGO前瞻20.go多版本管理21.openAI发布v0.2.0了22.Gin中间件开发23.Fabric区块链浏览器(1)24.每日一库:Memcache25.protojson简介26.每日一库:gosec27.Fabric区块链浏览器(2)28.每日一库:fsnotify简介29.gRPC with JWT30.embed简介31.Fabric区块链浏览器(3)32.每日一库:pprof简介33.go 1.21:cmp34.完全可复制、经过验证的 Go 工具链35.PGO in Go 1.2136.Fabric 2.x 智能合约开发记录37.为不断增长的Go生态系统扩展gopls38.每日一库:lumberjack -- 日志轮换和管理
39.2023-04-26-微信安全模式下消息解析
40.WASI support in Go41.每日一库:Prometheus42.如何实现流量控制和熔断降级?43.消息队列 - RabbitMQ44.Go 1.22 中的 For 循环45.设计模式之单例模式46.每日一库:使用Viper处理Go应用程序的配置47.使用 gopkg.in/yaml.v3 解析 YAML 数据48.在Go中如何实现并发49.解析类型参数50.设计模式之工厂模式51.每日一库:cobra 简介52.slices in Go 1.2153.go defer简介54.slice简介55.Golang Map底层实现简述56.Go 如何实现多态57.查找数组中第K大的元素58.go中的内存逃逸59.数组 vs. 切片60.队列(Queue):先进先出(FIFO)的数据结构61.go 中如何实现定时任务62.go 中的循环依赖63.Go中字符串处理:fmt.Sprintf与string.Builder的比较64.理解Go中的零值65.go 上下文:context.Context66.go中异常处理流程67.Go实现网络代理68.Why gRPC ?69.Go:条件控制语句70.Go 获取 IP 地址71.Golang并发控制方式有几种?72.Golang面试:泛型73.LRU算法简介74.MRU算法实现75.ARC算法实现76.Go语言中的交互式CLI开发:survey库简介77.C如何调用Go在微信公众号的使用过程中,为了提高信息传输的安全性,可以在服务器配置中将消息加解密模式指定为安全模式。
启用安全模式后,公众号主动调用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: 恋水无意
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程