准备知识:

  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

服务端解密流程:

  1. 密文和偏移向量由客户端发送给服务端,对这两个参数在服务端进行Base64_decode解编码操作。
  2. 根据3rdSessionId从缓存中获取session_key,对session_key进行Base64_decode可以得到aesKey,aes密钥。
  3. 调用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();
    }

小程序encryptedData的更多相关文章

  1. 微信小程序java8 java7 java6 encryptedData 解密 异常处理

    使用java8 java7  java6 解密微信小程序encryptedData可以回遇到一些错误 1.java.security.NoSuchAlgorithmException: Cannot ...

  2. 小程序解密 encryptedData 获取 unionID 等信息

    index.php <?php include_once "wxBizDataCrypt.php"; // $appid 由小程序微信官方后台获取 $appid = 'wx4 ...

  3. 小程序Openid 获取,服务器 encryptedData 解密 遇到的坑

    获取客户 openId 和 unionId 需要以下步骤(都为必须步骤) 1.从验证从客户端传上来code, 获取sessionKey (需要配合小程序appid ,secret 发送到微信服务器) ...

  4. 微信小程序获取用户信息,解密encryptedData 包括敏感数据在内的完整用户信息的加密数据

    package com.iups.wx.wxservice; import java.io.UnsupportedEncodingException; import java.security.Alg ...

  5. .NET 小程序 wx.getUserInfo(OBJECT) 解密 encryptedData 来获取UnionId

    在小程序中通过 wx.getUserInfo 获取用户信息,而UnionId 只有关主了公众号才会返回,不关注公众号想获取UnionId则需要我们从返回的 encryptedData 中解码从而获取U ...

  6. 小程序登录解密用户数据encryptedData -41001: encodingAesKey 非法

    问题: 做小程序微信授权登录,先获取code,然后去获取到session_key和open_id,再拿到encryptedData,传到服务器去解密拿到用户信息,但是有时成功,有时返回-41001错误 ...

  7. 微信小程序加密数据(encryptedData)解密中的PHP代码,php7.1报错

    问题描述 最近在开发微信小程序涉及到加密数据(encryptedData)的解密,用的是PHP代码,在运行后报错mcrypt_module_ xxx is deprecated,提示方法已过时了 经研 ...

  8. 微信小程序之用户数据解密(七)

    [未经作者本人同意,请勿以任何形式转载] 经常看到有点的小伙伴在群里问小程序用户数据解密流程,所以打算写一篇关于小程序用户敏感数据解密教程: 加密过程微信服务器完成,解密过程在小程序和自身服务器完成, ...

  9. 微信小程序-登陆、支付、模板消息

    wx.login(OBJECT) 调用接口获取登录凭证(code)进而换取用户登录态信息,包括用户的唯一标识(openid) 及本次登录的 会话密钥(session_key).用户数据的加解密通讯需要 ...

随机推荐

  1. C#操作Exchange配置

    1.客户端配置:运行gpedit.msc进入本地组策略管理器,计算机配置>管理模版>Windows组件>WinRM>WinRM客户端启用允许未加密通信:启用受信任的主机并添加e ...

  2. Head First Android --- Enable USB debugging on your device

    1. Enable USB debugging on your device    On your device, open “Developer options” (in Android 4.0 o ...

  3. Centos7系统下编写systemd脚本设置redis开机自启动

    今天想设置redis开机自启动,我觉得这样子比较好,但是在网上找了很长时间发现大家都是基于chkconfig的写法来设置的,并不能由systemd进程来统一管理,所以这里我自己编写了一个,希望大家可以 ...

  4. ccf-20170303--Markdown

    我的想法如下图: 代码和题目如下: 问题描述 试题编号: 201703-3 试题名称: Markdown 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 Markdown 是一 ...

  5. .NET 序列化成XML, 并且格式化

    现有Person类: [Serializable] public class Person { public string Name; public string Info; public Perso ...

  6. Linux 小知识翻译 - 「路径设置」

    这次聊聊路径的使用,这里的路径是「命令搜索路径」的简称. 在Linux上执行命令的时候,本来是需要命令的所在位置的绝对路径的,就像「/usr/bin/passwd」这样. 但是,对于经常使用的命令,如 ...

  7. February 2nd, 2018 Week 5th Friday

    Reputation takes a life time to build and a second to destroy. 树立名声需要一生的努力,而毁掉它只需要一秒. To be a smart ...

  8. Beta冲刺(3/5)(麻瓜制造者)

    今日已完成 邓弘立:完成了登录功能的重构,完成了部分商品管理功能 符天愉:利用ci开始写队友写好的管理员界面,由于后台独立开始使用一个仓库,所以晚上将alpha的版本更新到了git,并且添加了.git ...

  9. SAP中的ALE, IDOC

    ALE技术:应用链接支持(Application Link Enabling 简称ALE),是一项用于创建和运行分布式应用的技术.ALE是SAP的专有技术. ALE对象——ALE包含了可控的数据消息交 ...

  10. 如何在sublime编辑器中,执行命令行脚本

    我有个愿意,在执行命令行时,不打开那个黑乎乎命令行窗口,如果编辑器内置支持就好了. 打开vs code 和 sublime,分别按快捷键 Ctrl + ·(tab键上面那个键),vs code可以提供 ...