分享

微信开发(五)微信消息加解密 (EncodingAESKey)

 关平藏书 2018-02-07




消息体加密

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

原理

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

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

  1. <xml>  
  2.     <ToUserName><![CDATA[toUser]]></ToUserName>  
  3.     <FromUserName><![CDATA[fromUser]]></FromUserName>   
  4.     <CreateTime>1348831860</CreateTime>  
  5.     <MsgType><![CDATA[text]]></MsgType>  
  6.     <Content><![CDATA[this is a test]]></Content>  
  7.     <MsgId>1234567890123456</MsgId>  
  8. </xml>  

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

  1. <xml>  
  2.     <ToUserName><![CDATA[toUser]]></ToUserName>  
  3.     <Encrypt><![CDATA[encryptData]]></Encrypt>  
  4. </xml>  

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

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

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

代码实现

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

  1. public class SignUtil {  
  2.     /** 
  3.      *  与开发模式接口配置信息中的Token保持一致 
  4.      */  
  5.     private static String token = "yourToken";  
  6.       
  7.     /** 
  8.      * 微信生成的 ASEKey 
  9.      */  
  10.     private static String encodingAesKey ="yourKey";  
  11.   
  12.     /** 
  13.      * 应用的AppId 
  14.      */  
  15.     private static String appId="yourId";  
  16.       
  17.     /** 
  18.      * 解密微信发过来的密文 
  19.      *  
  20.      * @return 加密后的内容 
  21.      */  
  22.     public static String decryptMsg(String msgSignature,String timeStamp,String nonce,String encrypt_msg) {  
  23.         WXBizMsgCrypt pc;  
  24.         String result ="";  
  25.         try {  
  26.             pc = new WXBizMsgCrypt(token, encodingAesKey, appId);  
  27.             result = pc.decryptMsg(msgSignature, timeStamp, nonce, encrypt_msg);  
  28.         } catch (AesException e) {  
  29.             // TODO Auto-generated catch block  
  30.             e.printStackTrace();  
  31.         }  
  32.         return result;  
  33.     }  
  34.   
  35.     /** 
  36.      * 加密给微信的消息内容 
  37.      * @param replayMsg 
  38.      * @param timeStamp 
  39.      * @param nonce 
  40.      * @return 
  41.      */  
  42.     public static String ecryptMsg(String replayMsg,String timeStamp, String nonce) {  
  43.         WXBizMsgCrypt pc;  
  44.         String result ="";  
  45.         try {  
  46.             pc = new WXBizMsgCrypt(token, encodingAesKey, appId);  
  47.             result = pc.encryptMsg(replayMsg, timeStamp, nonce);  
  48.         } catch (AesException e) {  
  49.             // TODO Auto-generated catch block  
  50.             e.printStackTrace();  
  51.         }  
  52.         return result;  
  53.     }  

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

  1. //request 为请求的 HttpServletRequest 参数  
  2. String encrypt_type =request.getParameter("encrypt_type");  
  3. if (encrypt_type == null || encrypt_type.equals("raw")) { //不用加密  
  4.     // 微信加密签名    
  5.     String signature = request.getParameter("signature");    
  6.     // 时间戳    
  7.     String timestamp = request.getParameter("timestamp");    
  8.     // 随机数    
  9.     String nonce = request.getParameter("nonce");    
  10.         
  11.     if(SignUtil.checkSignature(signature, timestamp, nonce)) {  
  12.         //业务处理方法,返回为XML格式的结果信息 此处需要转换一下编码,否则中文乱码,不知为何...   
  13.         String respMessage = new String(wxService.processRequest(request.getInputStream(),session).getBytes("UTF-8"),"ISO8859_1");    
  14.         logger.info("message:"+respMessage);  
  15.         return respMessage;        
  16.     } else {  
  17.         return "check Error";  
  18.     }  
  19. } else {//需走加解密流程      
  20.     // 微信加密签名    
  21.     String msgSignature = request.getParameter("msg_signature");    
  22.     // 时间戳    
  23.     String timeStamp = request.getParameter("timestamp");    
  24.     // 随机数    
  25.     String nonce = request.getParameter("nonce");  
  26.     //密文  
  27.     String encryptMsg = readLine(request.getInputStream());  
  28.     
  29.     String data = SignUtil.decryptMsg(msgSignature, timeStamp, nonce, encryptMsg);  
  30.     logger.info("parse Data is:"+data);  
  31.     if(data.length() == 0) {  
  32.         return "CheckError";  
  33.     } else {  
  34.         InputStream istream = new ByteArrayInputStream(data.getBytes());  
  35.         //业务处理方法,返回为XML格式的结果信息  
  36.         String respMessage = wxService.processRequest(istream,session);  
  37.         logger.info("message:"+respMessage);  
  38.         String enRespMsg = SignUtil.ecryptMsg(respMessage, timeStamp, nonce);  
  39.         return enRespMsg;  
  40.     }  
  41. }  

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

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

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约