前面

上一篇文章手把手教会你小程序登录鉴权介绍了小程序如何进行登录鉴权,那么一般小程序的用户标识可以使用上文所述微信提供的jscode2session接口来换取,小程序还提供了一个getUserInfo的API来获取用户数据,这个用户数据里面也可以包含当前的用户标识openid。本文就如何获取小程序中的用户数据及数据完整性校验等内容来展开详述

API介绍

wx.getUserInfo是用来获取用户信息的API接口,下面是对应的参数字段:

字段 类型 是否必填
withCredentials Boolean
lang String
timeout Number
success Function
fail Function
complete Function

lang

lang 指定返回用户信息的语言,有三个值:

  • zh_CN 简体中文
  • zh_TW 繁体中文
  • en 英文,默认为en

timeout

timeout 指定API调用的超时时间, getUserInfoAPI其实底层也是客户端发起一个http请求,来获取到用户的相关数据,经过封装后返回给小程序端,后面会给大家详细介绍。

withCredentials

withCredentials 这个字段是一个布尔类型的值,决定了在调用API时小程序返回的数据里是否带上登录态信息,不填的话默认该字段的值为true

那么此时API返回的结果为:

字段 类型 描述
encryptedData String 加密后的用户数据
iv String 解密算法向量
rawData String 用户开放数据
signature String 签名
userInfo Object 用户开放数据

如果该字段的值为false,就不会返回上面这两个字段:encryptedData, iv

  • encryptedData 为包括敏感数据在内的完整用户信息的加密数据,敏感数据涉及到了用户的openidunionid等。那么数据加密采用的算法为AES-128-CBC分组对称加解密算法,后面我们对这个加密算法进行详细分析。

  • iv 为上述解密算法的算法初始向量。同样我们在后面会详细介绍。

  • rawData 为一个对象字符串,里面包含了用户的一些开放数据,分别是:nickName(微信昵称)province(所属省份)language(微信客户端内设置的语言类型)gender(用户性别)country(所在国家)city(所在城市)avatarUrl(微信头像地址)

  • signature 为了保证数据的有效性和安全性,小程序对明文数据进行了签名。这个值是sha1(rawData + session_key)计算后的值,sha1则是一种密码的哈希函数,相比于md5哈希函数来说抗攻击性更强。

  • userInfo 字段是一个对象,也是用户开放数据,和rawData展示的内容一致,只不过rawData将对象序列化为字符串作为返回值。

API之http请求

前面给大家讲到在客户端内调用getUserInfoAPI时,微信客户端会向微信服务端发送一条请求,在微信开发者工具里通过 http请求抓包可以看到,发出了一条https://servicewechat.com/wxa-dev-logic/jsoperatewxdata这样的http请求。

请求体里携带了几个重要的参数,包括data, grant_type等,data字段是一个JSON字符串,里面有一个字段api_name,其值为'webapi_userinfo'。而grant_type字段也对应了一个值“webapi_userinfo”。

响应体返回了一个JSON对象,首先是一个baseresponse字段,里面包含了接口调用的返回码errcode和调用结果errmsg。该对象还返回了一个data字段,这个data字段对应了一个JSON字符串,里面就是通过调用API拿到的所有用户数据信息。在开发者工具内,我们还可以看到返回了一个debug_info字段,这个里面同样包含了用户的数据data,只不过这里的data还返回了用户的openid,同时还返回了用户的session_key登录态凭据。

一般我们可以在开发者工具内通过抓包,来调试一些信息的有效性,包括用户的session_keyopenid

AES-128-CBC 加密算法

上面我们说过,在小程序里通过API获取到的用户完整信息encryptedData,是需要通过AES-128-CBC算法来加解密的。首先我们先来了解什么是AES-128-CBC

AES 全称为 Advanced Encryption Standard,是美国国家标准与技术研究院(NIST)在2001年建立了电子数据的加密规范,它是一种分组加密标准,每个加密块大小为128位,允许的密钥长度为128、192和256位。

分组加密有五种模式,分别是

ECB(Electronic Codebook Book) 电码本模式

CBC(Cipher Block Chaining) 密码分组链接模式

CTR(Counter) 计算器模式

CFB(Cipher FeedBack) 密码反馈模式

OFB(Output FeedBack) 输出反馈模式

这里我们主要来看AES-128-CBC的分组加密算法,即用同一组key进行明文和密文的转换,以128bit为一组,128bit也就是16byte,那么明文的每16字节为一组就对应了加密后的16字节的密文。如果最后剩余的明文不够16字节时,就需要进行填充了,通常会采用PKCS#7(PKCS#5仅支持填充8字节的数据块,而PKCS#7支持1-255之间的字节块)来进行填充。

如果最后剩余的明文为13个字节,也就是缺少了3个字节才能为一组,那么这个时候就需要填充3个字节的0x03:

明文数据:   05 05 05 05 05 05 05 05 05 05 05 05 05
PKCS#7填充: 05 05 05 05 05 05 05 05 05 05 05 05 05 03 03 03
复制代码

若明文正好是16个字节的整数倍,最后要再加入一个16字节0x10的组再进行加密。

因此,我们发现PKCS#7填充的两个特点:

  • 填充的字节都是一个相同的字节

  • 该字节的值,就是要填充的字节的个数

我们再来一起看明文加密的过程,CBC模式对于每个待加密的密码块在加密前会先与前一个密码块的密文进行异或运算,然后将得到的结果再通过加密器加密,其中第一个密码块会与我们前文所述的iv初始化向量的数据块进行异或运算。如下图(图片来自wiki百科):

但是需要明确说明的是,这里API返回的iv是解密算法对应的初始化向量,而非加密算法对应的初始化向量。所以大家肯定也就猜到了,CBC模式解密时第一个密码块也是需要和初始化向量进行异或运算的。如下图(图片来自wiki百科):

在小程序里,这里加密和解密的密码器为我们上一篇文章所获取到的经过base64编码的session_key

小程序中的应用

那么在前面我们大致了解了小程序中是如何对用户数据进行加密的之后,我们就一起以nodejs为例来看看如何在服务端对用户数据进行解密,以及解密后的数据完整性校验:

在util.js文件中,定义了两个方法:

decryptByAES方法是利用服务端在登录时通过微信提供的jscode2session接口拿到的session_key和调用wx.getUserInfo后将返回的iv初始化向量来解密encryptedData

encryptedBySha1方法是通过sha1哈希算法来加密session_key生成小程序应用自身的用户登录态标识,保证session_key的安全性。

// util.js
const crypto = require('crypto');
module.exports = {decryptByAES: function (encrypted, key, iv) {encrypted = new Buffer(encrypted, 'base64');key = new Buffer(key, 'base64');iv = new Buffer(iv, 'base64');const decipher = crypto.createDecipheriv('aes-128-cbc', key, iv)let decrypted = decipher.update(encrypted, 'base64', 'utf8')decrypted += decipher.final('utf8');return decrypted},encryptBySha1: function (data) {return crypto.createHash('sha1').update(data, 'utf8').digest('hex')}
};
复制代码

在auth.js文件中,调用了上篇文章里的getSessionKey方法,获取用户的openidsession_key,拿到这两者后,对加密的用户数据进行解密操作,同时将解密后的用户数据及用户的session_key和skey存入数据表中。

这里需要注意到一点:如果当前小程序绑定了开放平台的移动应用或网站应用,或公众平台的公众号等,那么encryptedData还会多返回一个unionId的字段,这个unionId可在小程序和其他已绑定的平台之间区分用户的唯一性,也就是说同一用户,对同一个微信开放平台下的不同应用,unionid是相同的。一般,我们可以用unionId来打通小程序和其他应用之间的用户登录态。

// auth.js
const { decryptByAES, encryptBySha1 } = require('../util');
return getSessionKey(code, appid, secret).then(resData => {// 选择加密算法生成自己的登录态标识const { session_key } = resData;const skey = encryptBySha1(session_key);let decryptedData = JSON.parse(decryptByAES(encryptedData, session_key, iv));// 存入用户数据表中return saveUserInfo({userInfo: decryptedData,session_key,skey})}).catch(err => {return {result: -10003,errmsg: JSON.stringify(err)}})
复制代码

校验数据完整性和有效性

当我们通过解密拿到用户的完整数据后,可以对拿到的数据进行数据的完整性和有效性校验,防止用户数据被恶意篡改。这里说明如何进行相关的数据校验:

有效性校验:在前面我们介绍到,当withCredentials设置为true时,返回的数据还会带上一个signature的字段,其值是sha1(rawData + session_key)的结果,开发者可以将所拿到的signature,在自己服务端使用相同的sha1算法算出对应的signature2,即

signature2 = encryptedBySha1(rawData + session_key);
复制代码

通过对比signature与signature2是否一致,来确定用户数据的完整性。

完整性校验:在前面拿到的encryptedData并进行相关解密操作后,会看到用户数据的object对象里存在一个watermark的字段,官方称之为数据水印,这个字段结构为:

"watermark": {"appid":"APPID","timestamp":TIMESTAMP
}
复制代码

这里开发同学可以校验watermark内的appid和自身appid是否一致,以及watermark内的数据获取的timestamp时间戳,来校验数据的时效性。

最后

那么上面就是小程序中如何对用户数据进行加解密操作,以及如何对用户数据进行相关处理和校验的介绍,请大家多多指教!

参考文章:

密码算法详解——AES

AES五种加密模式(CBC、ECB、CTR、OCF、CFB)

对加密算法 AES-128-CBC 的一些理解

高级加密标准AES的工作模式(ECB、CBC、CFB、OFB)


《IVWEB 技术周刊》 震撼上线了,关注公众号:IVWEB社区,每周定时推送优质文章。

  • 周刊文章集合: weekly
  • 团队开源项目: Feflow

小程序中神秘的用户数据相关推荐

  1. 微信小程序中如何获取用户手机号授权登录

    随着微信小程序的普及,许多应用程序需要用户登录才能提供更好的服务.而获取用户手机号码是验证用户身份和确保账户安全的重要步骤之一.因此,在本文中,我们将介绍如何在微信小程序中实现手机号授权登录. 步骤一 ...

  2. 微信小程序开发系列五:微信小程序中如何响应用户输入事件

    微信小程序开发系列教程 微信小程序开发系列一:微信小程序的申请和开发环境的搭建 微信小程序开发系列二:微信小程序的视图设计 微信小程序开发系列三:微信小程序的调试方法 微信小程序开发系列四:微信小程序 ...

  3. 微信小程序中处理 获取用户地址的回调

    handleChooseAddress () {// 选择用户地址,初次调用该方法会弹出授权窗口,授权信息会被保存到 scope.address 属性中// 如果用户点击的是[取消],scope.ad ...

  4. 小程序中实现获取全部数据

    日常在开发小程序的时候,我们的后端服务可以采用云开发的模式,但是云开发限制每次最多获取100条的数据,如果我们需要获取全部数据,必须自己构造后端服务.本篇我们介绍一下如何获取全部数据. 定义api 微 ...

  5. 微信小程序中获取微信用户绑定的手机号getPhoneNumber

    调用getPhoneNumber之前先调用wx.login接口,获取登录凭证(code),通过凭证进而获取用户登录态信息(包括openid及session_key) ----------------- ...

  6. 微信小程序中用户登录和登录态维护

    微信小程序和以前的web项目不同,他是前后端分离的应用,之前我们的传统登录有web服务器提供Session维护, 后端在返回结果给前端web项目时,带上cookie,且以cookie值为key存储用户 ...

  7. 小程序中引导用户关注公众号

    众所周知,小程序现在越来越普遍,应市场需求,越来越多的开发者在学习小程序的开发,因为小程序刚起步,所以有很多问题还不完善,微信开放平台也在日渐完善,小程序文档也在不断优化,现在小程序中可以引导用户关注 ...

  8. 在微信小程序中,如果自动获取用户所在的省市地区?

    可以通过微信小程序提供的API获取用户所在的省市地区信息.具体步骤如下: 在小程序中需要获取用户地理位置时,需要先在app.json中配置"permission"字段,并开启用户授 ...

  9. 微信小程序中的数据请求

    目录 前言 一.网络数据请求的限制 二.配置 request 1. 修改request域名需要注意哪些? 2. 发起`GET`请求 3. 发起 `POST` 请求 4. 在页面刚加载的时候请求数据 5 ...

最新文章

  1. 对系统故障处理的思考
  2. Centos 7 yum 安装php
  3. jvm:运行时数据区--方法返回地址
  4. 理解值和对象-快照图
  5. Reversing Ethereum Smart Contracts: Part 2
  6. c语言倒序输出字符串数组,【C语言】利用栈将数组中字符串逆序
  7. lua的面向对象编程,封装,继承,多态的实现
  8. 数据结构学习之路-第一章:绪论
  9. 前端学习(2459):账户设置
  10. PHP报错: Can't use method return value in write context
  11. 小学计算机课动画制作的评课稿,信息技术2.0 | 评课磨课共成长 信息技术促进步 ——东光县第二实验小学信息技术2.0课例研讨...
  12. Codesys和基恩士扫码枪Ethernet/IP通信
  13. 关键词抽取——结巴分词
  14. 2022年~全网最真实的软件测试面试题合集
  15. 2017年数据库技术盘点
  16. “大多数”餐馆收银系统被用于盗用信用卡信息的恶意软件感染
  17. 最长等差数列_最长等差子序列的长度
  18. Ubuntu安装Node.js(亲测,最新,详细)
  19. html字两边的横线_css实现中间文字两边横线效果
  20. 百慕大三角新奇神秘事件

热门文章

  1. CentOS 7 的 32 位版发布
  2. mysql字段说明_mysql 字段类型说明
  3. mysql cluster 读写分离_mysql数据库集群实现高可用读写分离_一点课堂(多岸学院)...
  4. 串匹配算法——BF算法
  5. 回溯法——旅行售货员问题
  6. linux大端小端命令,linux的大小端、网络字节序问题
  7. java https jasonrpc_以太坊 ethereum JSON-RPC java 调用示例
  8. python列表元素替换的数据结构_Python基础学习数据结构(第2讲:列表;第2讲:列表创建、添加元素、插入元素、替换元素、删除元素、其他常用方法和列表派生),第二,主讲,追加,推导,式...
  9. lsof查看占用高_查看端口占用情况lsof,并关闭对应进程kill
  10. autosys file watcher 注意事项