微信开发加密消息_微信开发消息加密原理 - CSDN
  • 由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文...微信接入被动回调接口时有一个安全模式,它是做什么的?如何适配安全模式呢?带着这些问题,来进入微信接入的第三次探秘之旅。

    本文出处:http://blog.csdn.net/chaijunkun/article/details/53435972,转载请注明。由于本人不定期会整理相关博文,会对相应内容作出完善。因此强烈建议在原始出处查看此文

    在上一篇博文中,介绍了被动回调接口的抽象数据层次,并实现了一个高效的实体与XML互转的基础功能。细心的开发者在初次修改公众号的基本配置时会发现一个名为“消息加解密方式”的选项。展开后可供选择的值为:“明文模式”(默认)、“兼容模式”和“安全模式(推荐)”。那么这个安全模式又是什么呢?如何适配安全模式呢?带着这些问题,来进入微信接入的第三次探秘之旅。

    本专栏代码可在本人的CSDN代码库中下载,项目地址为:https://github.com/chaijunkun/wechat-common

    可恶的流量劫持

    在文章的一开始,先给大家看两幅处于正常使用中的手机屏幕截图:

    2016年9月北京联通的流量劫持

    在屏幕的右下角你会看到都有个绿色的水球显示,这与要显示的画面格格不入,很明显不是设计者为之。点开水球,显示的是当前通讯套餐中剩余的流量详情。

    经过多方查证,它来自于北京联通。运营商强制将自己的代码注入到了当前显示的页面当中。也就是说,ISP在没经过用户同意的前提下,拦截了我们访问的内容,经过篡改后再返回给我们。例子中仅仅是流量提醒,有一些小规模的ISP甚至过分到直接私自插入广告。面对运营商级别的不法侵害,只有技术升级,采取一定的加密手段才能防止数据被非法篡改,其中HTTPS就是很好的方式。这也是为什么淘宝、京东等公司在全站实现HTTPS,

    中间人监听

    从家庭局域网络到Internet再到IDC机房内网,我们的数据链路充满了转发的过程。我们的数据在经过任何一台设备的转发时都有可能被其持久化保存起来。你的办公内网一定安全吗?潜伏在你身边的黑客,通过设置局域网内某个网卡为混杂模式(Promiscuous Mode)可以将局域网中的所有数据都接收一份。可能你并不能发现什么,然而你的私有数据已经被别人窃取。

    使用安全模式保护用户隐私

    微信的被动回调接口提供了一套基于消息加密的防范措施,来抵御这些我们面临的众多安全威胁。这里请注意,如果你提供的回调地址是https协议的,那么开启明文模式即可,因为整个传输链路层对你来说已经是安全的了。

    安全模式的回调数据格式

    当启用安全模式之后,被动回调接口接收到的消息就产生了很大的变化,形式如下所示:

    <xml>
        <ToUserName><![CDATA[gh_38a2de904e09]]></ToUserName>
        <Encrypt><![CDATA[i7b8ccNA9OWDhau/F26aUWKFJ6Jd0imsDQIFPSdSfAg8mHT7rL0kIWSVpcqf6/dVSoOQOQK4T/CS3w96j4k3qcg89M6xn2RGZBs+9JkrsdRig5yhcia1B59akWb1t9QdutXqnl4edAqtXEh8SIs+N2HkOTTVldtOUHpdwLqRYuC4F6ejUoXui4xKuc3oyODR9edfL+xzZ7JfMJ1KUNF/YBJMj/Ba9y/CLLYmdFYOtCMH7tMUz8h+S0XKkHKN6r0ELLCIZJ9+PPlHZcfSGhwMLUeRF1nMIjXGEKHkI0uMcruh7wD96lMU/RFgJDjAk26xbmUYfa3l+34p+txw4R8iD3Q58S8Yekiy3lUsbk+C6eDeefGs1ck23BQ8xWU3AReWH2dEsY6SYIkb3ANeyJmcoIKZfpc/31njp0KcHAxL1Lk=]]></Encrypt>
    </xml>
    

    可以看出,明文部分保留了该消息的公众号原始ID:gh_38a2de904e09,其余部分均为加密文本(这种结构可以使得同一个后台系统,接入多个公众号,再利用每个公众号的设置进行分别解密)。由于加密结构在官方文档(http://qydev.weixin.qq.com/wiki/index.php?title=加解密库下载与返回码)中并没有明确的阐述,这里就给大家详细地说明一下。

    文本密文字节密文字节数据16字节随机数4字节内容长度标识明文数据appIdBase64解码AES解密提取提取得到明文长度n从长度标识后读取n字节,UTF-8编码记录明文结束点m从明文结束点m读到末尾,UTF-8编码文本密文字节密文字节数据16字节随机数4字节内容长度标识明文数据appId

    如果读者以前开发过网络协议应该很容易理解这个结构,典型的不定长消息。一定会有一个标识来指明不定长区域的长度,读取时以该值为准,在定长数据之后读取若干字节。在结构的开头,有16字节随机数,该部分数据无实际意义,可用于后续返回加密消息时作为随机数的填充数据。

    安全模式的签名验证方法

    微信的被动回调接口实际上是一个HTTP POST请求,我们都知道HTTP请求分为请求头和请求体。微信巧妙地将加密的XML数据放在了请求体,将验证签名时使用的参数放入了请求头。

    POST /cgi-bin/wxpush? msg_signature=477715d11cdb4164915debcba66cb864d751f3e6&timestamp=1409659813&nonce=1372623149 HTTP/1.1
    Host: qy.weixin.qq.com
    Content-Length: 613
    <xml>
    	<ToUserName><![CDATA[wx5823bf96d3bd56c7]]></ToUserName>
    	<Encrypt><![CDATA[RypEvHKD8QQKFhvQ6QleEB4J58tiPdvo+rtK1I9qca6aM/wvqnLSV5zEPeusUiX5L5X/0lWfrf0QADHHhGd3QczcdCUpj911L3vg3W/sYYvuJTs3TUUkSUXxaccAS0qhxchrRYt66wiSpGLYL42aM6A8dTT+6k4aSknmPj48kzJs8qLjvd4Xgpue06DOdnLxAUHzM6+kDZ+HMZfJYuR+LtwGc2hgf5gsijff0ekUNXZiqATP7PF5mZxZ3Izoun1s4zG4LUMnvw2r+KqCKIw+3IQH03v+BCA9nMELNqbSf6tiWSrXJB3LAVGUcallcrw8V2t9EL4EhzJWrQUax5wLVMNS0+rUPA3k22Ncx4XXZS9o0MBH27Bo6BpNelZpS+/uh9KsNlY6bHCmJU9p8g7m3fVKn28H3KDYA5Pl/T8Z1ptDAVe0lXdQ2YoyyH2uyPIGHBZZIs2pDBS8R07+qN+E7Q==]]></Encrypt>
    </xml>
    

    签名生成的过程

    接入配置请求时间戳随机字符回调加密XMLToken参数收集容器拼接字符串签名从头部获取从头部获取从请求体获取读取装入装入装入装入按字典序排序取SHA1摘要接入配置请求时间戳随机字符回调加密XMLToken参数收集容器拼接字符串签名

    通过上述计算,现在得出了当前加密消息的签名calculated_sign,然后从请求头中获取参数msg_signature,如果calculated_sign和msg_signature相同,则说明消息没有被篡改过。这种签名策略利用的数学难题有:

    1. SHA1摘要算法对全部数据进行了计算,有任何改动最终的摘要都会发生变化;
    2. Token是事先设置好的,在传输过程中并不包含,无从破解;
    3. 时间戳和随机字符的引入,使得即便明文相同,每一次加密密文都有不同,给破解AES加密增加难度

    签名验证成功之后就可以放心地使用解密后的明文了。明文的格式和之前文章中介绍的格式一致,因此解密后的业务处理逻辑可以复用。

    作为安全模式的应答,返回的XML格式也应该是加密的,整个加密过程与解密过程方向相反,这里就不再赘述了。

    2017年5月26日补充:微信的加密消息核心使用AES方式加密。在生产环境中,由于解密消息超过了JDK默认的安全限制值,解密时会抛出异常java.security.InvalidKeyException:illegal Key Size。解决该问题可以在官方网站下载JCE无限制权限策略文件:
    a.如果使用的是JDK7:下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce-7-download-432124.html
    b.如果使用的是JDK8:下载地址:http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
    下载后解压,可以看到local_policy.jar和US_export_policy.jar以及readme.txt。
    如果安装了JRE,将两个jar文件放到%JRE_HOME%\lib\security目录下覆盖原来的文件,如果安装了JDK,将两个jar文件放到%JDK_HOME%\jre\lib\security目录下覆盖原来文件。

    展开全文
  • 随着微信服务开发在越来越多的领域应用,应用的安全性逐渐被重视起来。本文主要阐述如何为微信消息加密的原理与Java版本的实现。


    文章作者:松阳

    本文出自 阿修罗道,禁止用于商业用途,转载请注明出处。  

    原文链接:http://blog.csdn.net/fansongy/article/details/44005301

    width="150" height="210" frameborder="0" scrolling="no" src="http://widget.weibo.com/relationship/bulkfollow.php?language=zh_cn&uids=2080045857&wide=1&color=FFFFFF,FFFFFF,0082CB,666666&showtitle=0&showinfo=1&sense=0&verified=1&count=1&refer=http%3A%2F%2Fwww.himigame.com%2Fandroid-game%2F1521.html&dpc=1" style="font-size: 14px; font-weight: bold; border-width: 0px; margin: 0px; padding: 0px; font-family: arial, helvetica, clean, sans-serif; line-height: 16px;">







    消息体加密

    随着微信服务开发在越来越多的领域应用,应用的安全性逐渐被重视起来。本文主要阐述如何为微信的消息加密的原理与Java版本的实现。

    原理

    做过微信开发的朋友们都知道,微信使用xml格式的消息结构。这里着重说一下最核心的收发消息。

    在明文模式中,POST请求有signature, timestamp, nonce三个参数。它的Body为一个XML:

    <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <FromUserName><![CDATA[fromUser]]></FromUserName> 
        <CreateTime>1348831860</CreateTime>
        <MsgType><![CDATA[text]]></MsgType>
        <Content><![CDATA[this is a test]]></Content>
        <MsgId>1234567890123456</MsgId>
    </xml>

    而在加密模式中,增加了两个参数:encrypt_typemsg_signature 。它的Body 也变更为:

    <xml>
        <ToUserName><![CDATA[toUser]]></ToUserName>
        <Encrypt><![CDATA[encryptData]]></Encrypt>
    </xml>

    其中encryptData是加密后的信息,通过我们在微信开发平台配置的EncodingAESKey, Token, 以及自动生成的AppID,通过加密算法,可以验证信息的真实性,并且将真实的信息,解析成如明文的格式的XML。整条信息是加密的,因此不用担心被伪造,否则,会有风险。

    PS:会有怎样的风险?如果是Token被人猜出来进而伪造内容,加密模式中的EncodingAESKey不会么?还是担心消息类型会泄露?没太想明白,希望路过的大神指点

    不管怎么说,加密看起来更安全些,我现在做一个金融类的项目,有备无患,就使用了加密的功能。

    代码实现

    微信提供了一个各种语言的解析,我在上面稍微封装了一下:

    public class SignUtil {
        /**
         *  与开发模式接口配置信息中的Token保持一致
         */
        private static String token = "yourToken";
        
        /**
         * 微信生成的 ASEKey
         */
        private static String encodingAesKey ="yourKey";
    
        /**
         * 应用的AppId
         */
        private static String appId="yourId";
        
        /**
         * 解密微信发过来的密文
         * 
         * @return 加密后的内容
         */
        public static String decryptMsg(String msgSignature,String timeStamp,String nonce,String encrypt_msg) {
            WXBizMsgCrypt pc;
            String result ="";
            try {
                pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
                result = pc.decryptMsg(msgSignature, timeStamp, nonce, encrypt_msg);
            } catch (AesException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return result;
        }
    
        /**
         * 加密给微信的消息内容
         * @param replayMsg
         * @param timeStamp
         * @param nonce
         * @return
         */
        public static String ecryptMsg(String replayMsg,String timeStamp, String nonce) {
            WXBizMsgCrypt pc;
            String result ="";
            try {
                pc = new WXBizMsgCrypt(token, encodingAesKey, appId);
                result = pc.encryptMsg(replayMsg, timeStamp, nonce);
            } catch (AesException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return result;
        }

    最后,在对应POST的处理方法中调用:

    //request 为请求的 HttpServletRequest 参数
    String encrypt_type =request.getParameter("encrypt_type");
    if (encrypt_type == null || encrypt_type.equals("raw")) { //不用加密
        // 微信加密签名  
        String signature = request.getParameter("signature");  
        // 时间戳  
        String timestamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");  
          
        if(SignUtil.checkSignature(signature, timestamp, nonce)) {
            //业务处理方法,返回为XML格式的结果信息 此处需要转换一下编码,否则中文乱码,不知为何... 
            String respMessage = new String(wxService.processRequest(request.getInputStream(),session).getBytes("UTF-8"),"ISO8859_1");  
            logger.info("message:"+respMessage);
            return respMessage;      
        } else {
            return "check Error";
        }
    } else {//需走加解密流程    
        // 微信加密签名  
        String msgSignature = request.getParameter("msg_signature");  
        // 时间戳  
        String timeStamp = request.getParameter("timestamp");  
        // 随机数  
        String nonce = request.getParameter("nonce");
        //密文
        String encryptMsg = readLine(request.getInputStream());
      
        String data = SignUtil.decryptMsg(msgSignature, timeStamp, nonce, encryptMsg);
        logger.info("parse Data is:"+data);
        if(data.length() == 0) {
            return "CheckError";
        } else {
            InputStream istream = new ByteArrayInputStream(data.getBytes());
            //业务处理方法,返回为XML格式的结果信息
            String respMessage = wxService.processRequest(istream,session);
            logger.info("message:"+respMessage);
            String enRespMsg = SignUtil.ecryptMsg(respMessage, timeStamp, nonce);
            return enRespMsg;
        }
    }

    使用上面的方法,可以同时处理明文模式与加密模式,从真正意义上做到闲的蛋疼

    如果你觉得这篇文章对你有帮助,可以顺手点个,不但不会喜当爹,还能让更多人能看到它... 

    展开全文
  • 微信开发的第一步就是要打通本地开发环境与微信服务器之间通道,所以我们在将内网(本地)端口映射到外网后,还要有一种特定的暗号来与微信服务器对接,就是加密认证。 在接口配置信息中填入自己的外网代理地址和自...

    微信开发的第一步就是要打通本地开发环境与微信服务器之间通道,所以我们在将内网(本地)端口映射到外网后,还要有一种特定的暗号来与微信服务器对接,就是加密认证。

    在接口配置信息中填入自己的外网代理地址和自定token后,点击确认提交按钮,实际上微信服务器会向我们发送一个认证请求,其中包含:signature,nonce,timestamp,echostr

    {
        signature: 'xxxxxxxxxxxxxxxxx',
        nonce: 'xxxxxxxxxxxxxxxxxx',
        timestamp: 'xxxxxxxxxxxxxxxxxxxxxx',
        echostr: 'xxxxxxxxxxxxxxxxxxx'
    }
    

    而要求我们返回的响应消息是echostr,微信接收到匹配的响应消息就表示接头成功。

    但是处于安全考虑,我们本地(内网)地址是暴露到外网的,谁都能进来溜溜,所以我们也需要判断这个请求是否属于微信服务器,判断逻辑如下:

    1 将token、timestamp(时间戳)nonce(随机数)三个参数进行字典排序
    2 将三个参数数字字符串拼接成一个字符串进行sha1加密
    3 将加密后的字符串与signature对比,如果相同,表示这个请求来源于微信

    代码如下:

    var str = [token,timestamp,nonce].sort().join('');
    var sha = Sha1(str);
    
    if (sha === signature) {
      this.body = echostr
    }else {
      this.body = 'wrong'
    }

    微信加密认证的过程其实非常简单,但我们要注意代码不能敲错,出现配置错误第一步是查看控制台,请求有没有发过来,然后检查代码拼写

    通常会把加密认证做成中间件来简化代码逻辑,这里不做阐述。

    展开全文
  • 微信加密消息主要下面几个方面的内容: 加密前明文结构 16字节的随机字符串 消息长度的网络子节序 加密方式 加密算法 填充块计算方式 加密实现 1. 加密前明文结构: ra

    最近在做微信接入,在采用明文消息与微信服务器进行通信时,毫无压力,改成密文后,微信提供了各种语言版本的demo,but 没有nodejs。(复制一下,语文偏科,凑字数)。

    做微信加密消息主要下面几个方面的内容:

    1. 加密前明文结构

    2. 16字节的随机字符串

    3. 消息长度的网络子节序

    4. 加密方式

    5. 加密算法

    6. 填充块计算方式

    7. 加密实现

    1. 加密前明文结构: random(16B)+ msg_len(4B) + msg + $AppId;

            说明:random(16B)为16字节的随机字符串;msg_len为msg长度,占4个字节(网络字节序),$AppId为公众账号的AppId

    2. 16字节随机字符串:没啥说的直接拼接就好了


    var randomPrefix = function(n) {
        var _str = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890';
        var buf = new Buffer(n);
        for (var i = 0; i < n; i++) {
            buf[i] = _str.charCodeAt(Math.floor(Math.random() * _str.length));
        }
        return buf;
    };

    3. 网络子节序:网络子节序根据消息主体长度而生成

    var htonl = function(n) {
        var buf = new Buffer(4);
        buf[0] = (n & 0xFF000000) >> 24;
        buf[1] = (n & 0x00FF0000) >> 16;
        buf[2] = (n & 0x0000FF00) >> 8;
        buf[3] = (n & 0x000000FF) >> 0;
        return buf;
    };

    4.加密方式:Base64_Encode(AES_Encrypt [random(16B)+ msg_len(4B) + msg + $AppId]);

    5.加密算法:AES采用CBC模式,秘钥长度为32个字节,数据采用PKCS#7填充;PKCS#7:K为秘钥字节数(采用32),buf为待加密的内容,N为其字节数。Buf需要被填充为K的整数倍。在buf的尾部填充(K-N%K)个字节,每个字节的内容是(K- N%K);

    6.填充块计算方式: 消息体长度 /32 ,

    var padding = function(n) {
        var len = n % 32;
        if (len == 0) { 
            len = 32;
        } else {
            len = 32 - len;
        }
        var buf = new Buffer(len);
        for (var i = 0; i < len; i++) {
            buf[i] = len;
        }
        return buf;
    };

    7.加密实现:

        1.加密采用crypto库,

        2.加密方式:aes-256-cbc,

        3.key:

    var encodingAESKey = new Buffer("YfWVs4vtcNf6FPFRqzJ2VT6LCmpppePaRyGJjt7Rlcr" + "=", 'base64');

     4.IV:

    encodingAESKey.slice(0, 16);

    5. 创建加密对象方法:createCipheriv,

    var cipher = crypto.createCipheriv('aes-256-cbc', encodingAESKey, encodingAESKey.slice(0, 16));

    6. 取消自动填充

    cipher.setAutoPadding(false);

    7.加密并返回结果
    cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, corpBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据

    8.整体加密代码

    var encrypt = function(msg) {
        var msgBuf = new Buffer(msg, "utf-8"),
            msgBufLength = msgBuf.length,
            preBuf = randomPrefix(16),
            netBuf = htonl(msgBufLength),
            corpBuf = new Buffer(corpId, "utf-8"),
            corpBufLength = corpBuf.length,
            paddingBuf = padding(20 + msgBufLength + corpBufLength);
        var cipher = crypto.createCipheriv('aes-256-cbc', encodingAESKey, encodingAESKey.slice(0, 16)); 
        cipher.setAutoPadding(false); // 取消自动填充
        return cipher.update(Buffer.concat([preBuf, netBuf, msgBuf, corpBuf, paddingBuf]), "binary", 'base64') + cipher.final('base64'); // 解密数据
    };
    欢迎加入node.js交流群:572416249
    原文:http://my.oschina.net/lvyuely/blog/598421
    展开全文
  • 微信平台配置服务器,提供三种加密解密模式供开发者选择,明文,兼容,安全。选择兼容和安全模式之前,需要在开发者中心填写EncodingAESKey.公众号用这个秘钥对收到的密文进行解密,回复也用这个加密。 接口...
  • 微信公众号后台的运维,虽然一般只是纯后台形式的,一般人发现不了你的地址,但也不能掉以轻心,同学运维的一个公众号不仅没有任何防注入的措施,还使用了明文传输,我拿到他公众号后台地址之后,一个模拟请求提交...
  • Android 微信支付加密

    2019-08-28 16:30:55
    唯独这个微信,后台说是前端自己加密(真坑爹) 如何接入微信支付就不说了,重点加密 客户端微信加密 //activity中 private IWXAPI iwxapi; // PayUtils payUtils = new PayUtils(); //// //传递后台传递...
  • 说明:该篇博客是博主一字一码编写的,实属不易,请尊重原创,谢谢大家! ... 一丶概论 公众号接收与发送消息 ...如果公众号类型为服务号(订阅号只能使用普通消息接口),可以在公众平台网站中申请认证...
  • 错误出现场景:用户在微信公众号里面发送一条消息后,接口收到的加密数据,在解密的时候报错。 错误内容:java.security.InvalidKeyException: Illegal key size 错误原因描述:JRE本身中自带的“local_policy.jar...
  • 1.阅读“方案概述” http://mp.weixin.qq.com/wiki/index.php?title=%E6%96%B9%E6%A1%88%E6%A6%82%E8%BF%B0   2.下载Demo代码。   3.更新jdk的JCE无限制权限策略文件 jdk1.7到 ...
  • 只有被动回复消息(即粉丝向公众号发送消息,由微信服务器向公众号服务器转发xml结构,同时公众号服务器返回xml结构,由微信服务器转发给粉丝)可以设置加密.其他3种消息(群发消息,客服消息,模板消息)的调...
  • 简介: 本篇博文是针对本人在开发企业微信消息交互的一些经验分享,介绍一下自己开发过程中遇到的问题和解决方法,如果问题或异议,欢迎讨论,技术大佬请忽略 用户在企业微信中有2种用户操作可以发送给我们服务器 1...
  • 微信开发之入门教程

    2016-01-12 10:55:26
    微信开发也是有了一定的认识。在此,小宝鸽再次无私地分享给大家啦。其实微信开发跟web开发没有多大的区别,只是经过了微信,然后再由浏览器打开。因为经过微信,因此你的web会附加一些微信平台所提供的一些功能,...
  • 微信公众号中 微信与服务器通信 有一个安全模式 如下图我们看看微信自带的sdk 核心解密部分 然而这个 mcrypt_encrypt 在 php7.1.* 中 函数已经不允许使用那么问题来了 php7 速度极快 怎么才能用呢 我将微信...
  • 微信企业号的消息,分成两种,调用微信接口发送的消息在接口文档中叫做发送消息,这种消息是json格式的。在微信服务器给我们配置的URL post数据时发送的消息叫做接收消息和事件,需要加密解密,不需要调用微信接口,...
  • 消息加密模式有三种,如下图:在明文模式下我们不需要解密,但如果是加密模式提交的,我们要对得到的数据进行解密才能使用。一、首先要到官方网站下载示例文件。点这里下载... 1.拷贝包src.com.qq.weixin.mp.aes下的...
  • 2019独角兽企业重金招聘Python工程师标准>>> ...
  • 微信开发交流群:148540125系列文章参考地址 极速开发微信公众号欢迎留言、转发 项目源码参考地址 点我点我–欢迎Start 前几篇文章已讲完如何导入项目,如何启动配置项目,如何成为开发者(如果前三项不会的看这里...
  • 微信公众平台消息体签名及加解密实例,微信官方为了更高的安全性,10月份推出了消息体签名验证。网上关于此项的实例不多,其实根据官方的例子,重新封装一下,就可以了。
1 2 3 4 5 ... 20
收藏数 30,895
精华内容 12,358
关键字:

微信开发加密消息