首頁  >  文章  >  微信小程式  >  微信開發入門(六)用戶資料解密

微信開發入門(六)用戶資料解密

零下一度
零下一度原創
2017-05-24 09:38:082080瀏覽

經常看到有點的小夥伴在群組裡問小程式用戶資料解密流程,所以打算寫一篇關於小程式用戶敏感資料解密教學;

加密過程微信伺服器完成,解密過程在小程式與自身伺服器完成,即由encryptData 得到以下資料:

{
    "openId": "OPENID",
    "nickName": "NICKNAME",
    "gender": GENDER,
    "city": "CITY",
    "province": "PROVINCE",
    "country": "COUNTRY",
    "avatarUrl": "AVATARURL",
    "unionId": "UNIONID",
    "watermark":
    {
        "appid":"APPID",
        "timestamp":TIMESTAMP
    }
}

準備知識:

  1. ##Base64編解碼

  2. AES演算法、填滿模式、偏移向量

  3. session_key會話金鑰,以及怎麼儲存和取得

以上3點對於理解解密流程非常重要

根據官方文檔,我梳理了大致的解密流程,如下:

微信開發入門(六)用戶資料解密

  1. #小程式用戶端呼叫wx.login,回調裡麵包含

    js_code。

  2. 然後將js_code傳送到伺服器A(開發者伺服器),伺服器A向微信伺服器發起請求附帶js_code、appId、secretkey和grant_type參數,以換取使用者的openid和session_key(會話密鑰)。

  3. 伺服器A拿到session_key後,產生一個隨機數我們叫3rd_session,以3rdSessionId為key,以session_key + openid為value

    #快取redis memcached中;因為微信團隊不建議直接將session_key在網路上傳輸,由開發者自行產生唯一鍵與session_key關聯。其作用是:

    1. 將3rdSessionId傳回給客戶端,維護小程式登入狀態。

    2. 透過3rdSessionId找到使用者session_key和openid。

  4. 客戶端拿到3rdSessionId後快取到storage,

  5. 透過wx.getUserIinfo可以取得到使用者敏感資料encryptedData 。

  6. 客戶端將encryptedData、3rdSessionId和偏移量一起傳送到伺服器A

  7. 伺服器A根據3rdSessionId從快取中取得session_key

  8. #在伺服器A使用AES解密encryptedData,從而實現用戶敏感資料解密

#重點放在6、7、8三個環節。

AES解密三個參數:

  • 密文encryptedData

  • #金鑰aesKey

# #偏移向量iv

服務端解密流程:

#密文和偏移向量由客戶端傳送給服務端,對這兩個參數在服務端進行Base64_decode

解編碼

操作。
微信開發入門(六)用戶資料解密

根據3rdSessionId從快取取得session_key,對session_key進行Base64_decode可以得到aesKey,aes金鑰。

呼叫aes解密方法,演算法為 AES-128-CBC,資料採用PKCS#7填入。

下面結合小程式實例說明解密流程:

1. 微信登錄,取得使用者資訊

var that = this;wx.login({success: function (res) {
    //微信js_code
    that.setData({wxcode: res.code});
    //获取用户信息
    wx.getUserInfo({
        success: function (res) {
            //获取用户敏感数据密文和偏移向量
            that.setData({encryptedData: res.encryptedData})            that.setData({iv: res.iv})        }
    })}})

2. 使用code換取3rdSessionId

var httpclient = require('../../utils/httpclient.js')
VAR that = this//httpclient.req(url, data, method, success, fail)httpclient.req(  'http://localhost:8090/wxappservice/api/v1/wx/getSession',
  {
      apiName: 'WX_CODE',
      code: this.data.wxcode
  },
  'GET',
  function(result){
    var thirdSessionId = result.data.data.sessionId;
    that.setData({thirdSessionId: thirdSessionId})    //将thirdSessionId放入小程序缓存
    wx.setStorageSync('thirdSessionId', thirdSessionId)  },
  function(result){
    console.log(result)  });

3. 發起解密請求

//httpclient.req(url, data, method, success, fail)httpclient.req('http://localhost:8090/wxappservice/api/v1/wx/decodeUserInfo',
  {
    apiName: 'WX_DECODE_USERINFO',
    encryptedData: this.data.encryptedData,
    iv: this.data.iv,
    sessionId: wx.getStorageSync('thirdSessionId')  },
  'GET',
  function(result){
  //解密后的数据
    console.log(result.data)  },
  function(result){
    console.log(result)  });
4. 服務端解密實作(java)
/** * 解密用户敏感数据 * @param encryptedData 明文 * @param iv            加密算法的初始向量 * @param sessionId     会话ID * @return */@Api(name = ApiConstant.WX_DECODE_USERINFO)@RequestMapping(value = "/api/v1/wx/decodeUserInfo", method = RequestMethod.GET, produces = "application/json")public Map<String,Object> decodeUserInfo(@RequestParam(required = true,value = "encryptedData")String encryptedData,        @RequestParam(required = true,value = "iv")String iv,        @RequestParam(required = true,value = "sessionId")String sessionId){    //从缓存中获取session_key
    Object wxSessionObj = redisUtil.get(sessionId);    if(null == wxSessionObj){        return rtnParam(40008, null);
    }
    String wxSessionStr = (String)wxSessionObj;
    String sessionKey = wxSessionStr.split("#")[0];    try {
        AES aes = new AES();        byte[] resultByte = aes.decrypt(Base64.decodeBase64(encryptedData), Base64.decodeBase64(sessionKey), Base64.decodeBase64(iv));        if(null != resultByte && resultByte.length > 0){
            String userInfo = new String(resultByte, "UTF-8");            return rtnParam(0, userInfo);
        }
    } catch (InvalidAlgorithmParameterException e) {
        e.printStackTrace();
    } catch (UnsupportedEncodingException e) {
        e.printStackTrace();
    }    return rtnParam(50021, null);
}

5. AES解密核心程式碼

public byte[] decrypt(byte[] content, byte[] keyByte, byte[] ivByte) throws InvalidAlgorithmParameterException {    initialize();    try {
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding");
        Key sKeySpec = new SecretKeySpec(keyByte, "AES");

        cipher.init(Cipher.DECRYPT_MODE, sKeySpec, generateIV(ivByte));// 初始化 
        byte[] result = cipher.doFinal(content);        return result;
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();  
    } catch (NoSuchPaddingException e) {
        e.printStackTrace();  
    } catch (InvalidKeyException e) {
        e.printStackTrace();
    } catch (IllegalBlockSizeException e) {
        e.printStackTrace();
    } catch (BadPaddingException e) {
        e.printStackTrace();
    } catch (NoSuchProviderException e) {        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (Exception e) {        // TODO Auto-generated catch block
        e.printStackTrace();
    }
最後的效果如下:

如果你的小程式沒有綁定微信開放平台,解密的資料中不包含unionid參數小程式綁定微信開放平台連線

###總結######從解密的數據看,算得上敏感的數據只有appid;個人覺得openid不是敏感數據,每個用戶針對每個公眾號會產生一個###安全###的openid;openid只有在appid的作用域下可用。除非你的appid也洩漏了。 ######那麼可以從解密資料得到appid,微信小程式團隊是何用意呢?還是前面那句話,openid脫離了appid就什麼都不是,openid和appid一起為了方便小程式開發者做到不同小程式應用之間用戶區分與隔離,同時能夠將微信用戶體系與第三方業務體系結合。 ######所以我認為敏感資料解密的主要用處不是解密後回傳給客戶端,而是在服務端將微信用戶資訊融入自身業務當中。 ######【相關推薦】######1. ###微信公眾號平台源碼下載##########2. ###微信投票源碼####### ###3.### 微信啦啦外送2.2.4解密開源版微信魔術方塊原始碼######

以上是微信開發入門(六)用戶資料解密的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn