一.配置公众号消息加解密方式
在公众号官方管理后台->开发->基本配置->修改配置上有3种方式,如下:
其中,EncodingAESKey可以随机生成.
加解密方式说明:
1).明文模式:微信服务器向公众号服务器(即我们要处理的http://szuzsq.tunnel.qydev.com/weixin/index.php)发送的xml结构是原始的,没有加密.如下:
<xml> <ToUserName><![CDATA[gh_733c42e0aee9]]></ToUserName> <FromUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></FromUserName> <CreateTime>1468291653</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[i love you]]></Content> <MsgId>6306264631030309910</MsgId> </xml>
而公众号服务器向微信服务器回复的xml结构也是原始的,没有加密.如下:
<xml> <ToUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></ToUserName> <FromUserName><![CDATA[gh_733c42e0aee9]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml>
2).安全模式:微信服务器向公众号服务器发送的xml结构是加密之后的,如下:
<xml> <ToUserName><![CDATA[gh_733c42e0aee9]]></ToUserName> <Encrypt><![CDATA[5iQIChI9SHJ8AygPRlQXg0TjENPp/+gMsL8QWceqRXbmZa9tfwft9JtVMhsd6acMJjq7s/gi6E/dLoaJ5optAJ3ixUoHlsJSiryZC/wkFZkY4++HQEr9sj0wHbsT9UbbW/TfXY0t5pQtM62hQKHO/AUFHiXAJ31kQrcGY4QZHyJjQDS6bchvufhOnm8paDMak3HeTf0vMBzkSZcl78V23uq8wvV1rBx4K9uzPz6AZmfV2rLbaA5u/fsQFcntl8aDK19PZfZreawt0et3AXv1DgFZEciC8vlCxwta6mjuAEIdL81t4mfa8V28iD8ul+AjWEMKcHszBQqQUkG3BTItB/8o+8h6PLYD+ZsHEUBbPttRhrlo+UlfXTehtGPVnd97GZ72ImWXb5wIadKcGSgXzvRRkVv1zav3CTjRRZH5k8kLqIxso9VmjD4Un+IF8vKaJqAu0irYWFMWYIhQZZ9CQQ==]]></Encrypt> </xml>
而公众号服务器向微信服务器回复的xml结构也是加密之后的.如下:
<xml> <Encrypt><![CDATA[lSK3AQg4RCd3GvUpEVQiZSxBWpAgH3MJjoZIGGjd0rcO14H7JasE2O8bzA/0PusNfKuxMmcCsTq3vHlbrdvALSioQKlpl/QrNH15kelS0bG12UMJhxs1CDa+ES9IuZ4wR7Ra/Oa3kCUh9x0RKdxkAWa0+jgT3bOD0OESMWp8Iynx11QiMBSMzAiEneLUCrszUdV6eBUQvdLTXkrRWYWHdMjgbvb8psc3NyxqB7N0GOG6i7ibk/Zd1s8nsDrYYDFI/BDFgl/wOEBSFC5rWgsgCdhuUEDcnU3N1eb/veL+TJ7zDAImUUPMY/auhm7mBVQcWjpCXutIo03esQJaSGiDxfj4VVBoZslPQc3gUKzm1I4QzCVU27J8/mx41I6Zc54k]]></Encrypt> <MsgSignature><![CDATA[5b9bff5f6dd7075d4ec2f4bca880d8ada48c6c7d]]></MsgSignature> <TimeStamp>1468291653</TimeStamp> <Nonce><![CDATA[1528778891]]></Nonce> </xml>
3).兼容模式:微信服务器向公众号服务器发送的xml结构即有原始的,也有加密之后的,如下:
<xml> <ToUserName><![CDATA[gh_733c42e0aee9]]></ToUserName> <FromUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></FromUserName> <CreateTime>1468291484</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[i love you]]></Content> <MsgId>6306263905180836845</MsgId> <Encrypt><![CDATA[Kd1lnxCrEr4L3qT4De7Rp2nUgbnYj8M http:// <span style="font-family: Arial, Helvetica, sans-serif;">RpdCc4uTCwMMPkcSQ8KJmlx6rFnQPGh6gBqVaQJ20kXNKCYDQGQ1fur4Pbgydet8cDB+cvYitI/aRHo2KrVbXuJyiyuMuWw1zYWaeYmRCKN3+xyCtmtvPDBTW5PIJ7ZnUX0yGyp3J0oOjIJfULoVPqkUDY4W+Vdh0ZTR9eE7o0u9ioVUd+m5W72jsP61A7mivYCZTolCHWMFdhfoSQlxXm8tnTO1gu3v+vzTUCdWuZhpJNuD6X/Ab+vcgKSdopjlMKze8bUUw9CyT/YwEhj6CJRF46LkasUGC/i5wC7ABbTvZpGpMkuylF9pEY0E6PW+PwECsmY/aEcIp1CcsveddVJUeW9flOqgaDOiRvGyuwVMDTJo9inBuZpCRCGDUKpflBlUoD8nMbZzBxxVkUySjvmdj4Pa2V7gN2jRqtfmMtu9FzFcOyKUL/w==]]></Encrypt></span> </xml>
而公众号服务器向微信服务器回复的xml结构,则和安全模式下的回复是一样的.如下:
<xml> <Encrypt><![CDATA[lSK3AQg4RCd3GvUpEVQiZSxBWpAgH3MJjoZIGGjd0rcO14H7JasE2O8bzA/0PusNfKuxMmcCsTq3vHlbrdvALSioQKlpl/QrNH15kelS0bG12UMJhxs1CDa+ES9IuZ4wR7Ra/Oa3kCUh9x0RKdxkAWa0+jgT3bOD0OESMWp8Iynx11QiMBSMzAiEneLUCrszUdV6eBUQvdLTXkrRWYWHdMjgbvb8psc3NyxqB7N0GOG6i7ibk/Zd1s8nsDrYYDFI/BDFgl/wOEBSFC5rWgsgCdhuUEDcnU3N1eb/veL+TJ7zDAImUUPMY/auhm7mBVQcWjpCXutIo03esQJaSGiDxfj4VVBoZslPQc3gUKzm1I4QzCVU27J8/mx41I6Zc54k]]></Encrypt> <MsgSignature><![CDATA[5b9bff5f6dd7075d4ec2f4bca880d8ada48c6c7d]]></MsgSignature> <TimeStamp>1468291653</TimeStamp> <Nonce><![CDATA[1528778891]]></Nonce> </xml>
二.微信公众号加解密过程
写之前要重头吐槽一下,微信官方文档有2个地方https://mp.weixin.qq.com/wiki和http://mp.weixin.qq.com/wiki/home,这2个地方应该是1份新的,1份旧的.但是,我从微信公众号官方后台管理->开发->开发者工具->开发者文档,进入的是第1个地方,按理说应该是新的才对.但是在消息管理->发送消息-被动回复时加解密,这章节上,有一段话:"请开发者查看接入指引和开发者FAQ来接入消息体签名及加解密功能:接入指引,开发者FAQ,若关注技术实现,可查看技术方案:技术方案"在这段话里面,我怎么都找不着接入指引和开发者FAQ这些相关内容.后来,不记得如何,第2个地方,同样地方的同样一句话:"请开发者查看接入指引和开发者FAQ来接入消息体签名及加解密功能:接入指引,开发者FAQ,若关注技术实现,可查看技术方案:技术方案"在接入指引,开发者FAQ,技术方案这几处,是有链接的!!!!!!!这里再次鄙视下微信的文档人员!!!!!!!!.
好了,大家去围观接入指引,里面提到在安全和兼容模式下,微信服务器向公众号服务器转发消息的url上,会添加signature,timestamp,nonce,encrypt_type,msg_signature(注意signature和msg_signature不同)参数.例如:
http://szuzsq.tunnel.qydev.com/weixin/index.php?signature=35703636de2f9df2a77a662b68e521ce17c34db4×tamp=1468291653&nonce=1528778891&encrypt_type=aes&msg_signature=59e47c61f82b1ac655ea94a9ad214656f573ba5b
下载微信官方给出的示例代码: http://mp.weixin.qq.com/wiki/static/assets/a5a22f38cb60228cb32ab61d9e4c414b.zip,里面有C++、php、Java、Python和C#版本,我们只取用到的几个文件:errorCode.php,pkcs7Encoder.php,sha1.php,wxBizMsgCrypt.php,xmlparse.php,其中wxBizMsgCrypt.php实现了微信消息加解密的业务逻辑.
1).解密微信服务器向公众号服务器发送的xml.
<?php $errCode = $pc->decryptMsg($msg_signature, $timestamp, $nonce, $postStr, $decryptMsg); ?>
2).加密公众号服务器向微信服务器回复的xml.
<?php $errCode = $pc->encryptMsg($responseStr, $timestamp, $nonce, $encryptMsg); ?>
其中,$timestamp, $nonce即可以使用微信服务器在url中传进来的,也可以使用自己生成的.
三.完整示例
我的项目目录如下:
源文件如下:
<?php //文件名: http://szuzsq.tunnel.qydev.com/weixin/index.php require_once('aes/wxBizMsgCrypt.php'); define("TOKEN", "weixin"); define("AppID", "wxc5bc41cb7c73814f"); define("EncodingAESKey", "r0TTQS2o4xxlJcMjCs33leS56rpNJOi12QRldiXS5Lv"); $wechatObj = new wechatCallbackapiTest(); $wechatObj->responseMsg(); class wechatCallbackapiTest { public function responseMsg() { //微信服务器向公众号服务器发送xml $timestamp = $_GET['timestamp']; $nonce = $_GET["nonce"]; $msg_signature = $_GET['msg_signature']; $encrypt_type = $_GET['encrypt_type']; $postStr = file_get_contents('php://input'); //$GLOBALS["HTTP_RAW_POST_DATA"]; $pc = new WXBizMsgCrypt(TOKEN, EncodingAESKey, AppID); $decryptMsg = ""; //解密后的原文 $errCode = $pc->decryptMsg($msg_signature, $timestamp, $nonce, $postStr, $decryptMsg); error_log("**********************解密**********************\r\ntimestamp:$timestamp\r\nnonce:$nonce\r\nmsg_signature:$msg_signature\r\nencrypt_type:$encrypt_type\r\npostStr:$postStr\r\nerrCode:$errCode\r\ndecryptMsg:$decryptMsg\r\n\r\n", 3, "err.log"); //公众号服务器向微信服务器回复xml $responseStr = "<xml><ToUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></ToUserName><FromUserName><![CDATA[gh_733c42e0aee9]]></FromUserName><CreateTime>12345678</CreateTime><MsgType><![CDATA[text]]></MsgType><Content><![CDATA[你好]]></Content></xml>"; $encryptMsg = ''; //加密后的密文 $errCode = $pc->encryptMsg($responseStr, $timestamp, $nonce, $encryptMsg); error_log("**********************加密**********************\r\nresponseStr:$responseStr\r\nerrCode:$errCode\r\nencryptMsg:$encryptMsg", 3, "err.log"); echo $encryptMsg; } } ?>
效果如下:
代码中2处使用error_log打印出来的内容(为了好看,我后期手动排了下版),如下:
**********************解密********************** timestamp:1468298136 nonce:1156171062 msg_signature:5d7ad0fe355e800ab05092e62489469e27347bb6 encrypt_type:aes postStr: <xml> <ToUserName><![CDATA[gh_733c42e0aee9]]></ToUserName> <Encrypt><![CDATA[sI7OWIRI1LWe0OSH3aJbg1mIcirMiMQ7Seq8udJ0OAhrIVPKDqX2cf3tD9BPtyEgGIbQcnWIoJ6/JWjRuMSPjEcUgmpSZG1lAFb1YArPXwY2HIoi/n1mPK3E2Mntt55Y2Xp3/GlxuJxH/eg1rdad/98UfBiB5pJcmSM0odJJ+jQ1/ufIAn7fBFWwGpMeEOGtpX7mpMzVMxr5Y3qrNIIT6htnjW2nlwPFatGccHo0ne6BsRDzitLVKKOVUyIRLLcJopLb03GdAQPD3wVvUNtOKxlgvPt0gta09Z5AT6axqyBqB5Po+0TF4gNb8Q3eFJAZkl0fnzCQxnMZytf2NZ9mQjAf1lsTQfc68mCdyJ+y1g4pANvidZYpOKnfl1zI1edbIHKsdKhzWP+LX7neJtL7PNpj6Dzgm6og+z//NYR4JbiMv3DTizGywFbf112yoCiZu/ogeLbarav/5brdsbDZRA==]]></Encrypt> </xml> errCode:0 decryptMsg: <xml> <ToUserName><![CDATA[gh_733c42e0aee9]]></ToUserName> <FromUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></FromUserName> <CreateTime>1468298136</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[i love you]]></Content> <MsgId>6306292475303292097</MsgId> </xml> **********************加密********************** responseStr: <xml> <ToUserName><![CDATA[oIaodvwZe03Amjb8_jQ0ZHGmr-4w]]></ToUserName> <FromUserName><![CDATA[gh_733c42e0aee9]]></FromUserName> <CreateTime>12345678</CreateTime> <MsgType><![CDATA[text]]></MsgType> <Content><![CDATA[你好]]></Content> </xml> errCode:0 encryptMsg: <xml> <Encrypt><![CDATA[1XLHOG845Qa3YTE0/TO3bRg1EQCD+bNc93qumuX6tkYqXmlYA4nYhRDRLC8YeoJ19Zm0E5ZvoQ/+7YLNgtxwvj5OfhFoS0GYNLS9ka9rYLwePklKWa6tfbCtln75daHWFtLms95LGC8WZPFzixJhgkWh6cOvyGkMMxWkGc439qNbgbFklG1OGdzh5ae1KP7ywMtr6d5xfM6eEyBV+Mr/Fy0B3pxFMsnx/2yFUW3OCcpPL8PB0StfPgTRoTQbWwj0blxxXRNuQSasMErGd+up8xKe0kHpBZ4Hr4L6cnika+K2BXdR7ToVOGiQ37vRixNiyO34QVIb/I0AGo5LWLJxDP6Y4E7mhgKkJh4rSU6ihJ1YUZHljibKveO5s0syAEZ9]]></Encrypt> <MsgSignature><![CDATA[f41080b7fc392bd3c800d56c1479f307897cb628]]></MsgSignature> <TimeStamp>1468298136</TimeStamp> <Nonce><![CDATA[1156171062]]></Nonce> </xml>
研究的时候,借鉴了方倍工作室大神的博客<<微信公众平台开发者中心安全模式消息体加解密实现>>: http://www.cnblogs.com/txw1958/p/weixin-aes-encrypt-decrypt.html