目 录CONTENT

文章目录

小程序手机号一键获取,sessionKey解密失败问题分析

成培培
2025-04-17 / 0 评论 / 0 点赞 / 7 阅读 / 0 字

最近排查小程序登录的安全问题,主要问题就是通过wx.login()获取到临时登录凭证code,传给服务端获取sessionKey时,服务端把sessionKey返回到小程序了,导致第三方可以截获到这个sessionKey,后续调用一键获取手机号时,微信返回的手机号信息密文就可以给第三方解密替换,所以这个sessionKey任何时候都不能返回到小程序,这一点在微信公众平台的官方文档中也有提到:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
不过本文要介绍是另一个坑,就是sessionKey失效导致的手机号解密失败的问题

问题现象

最近发现小程序通过一键获取手机号的方式登录时,偶尔会出现使用sessionKey解密手机号失败的问题,特别是在一段时间没有使用,然后退出登录了再重新登录时特别容易出现。

产生原因

大致的代码如下:

<button open-type="getPhoneNumber" @getphonenumber="getPhoneNumber">手机号一键登录</button>

getPhoneNumber(e) {
	uni.login({
		provider: "weixin",
		success: async (res) => {
			let code = res.code
			let resp = await this.$http.getSessionKey({
				"authorizationCode": code
			})
			let openId = resp.data
	        let dataInfo = { ...e.detail }
			this.$http.decodePhoneInfo({
				"openId": openId,
				...dataInfo
			}).then(res => {
          // 解密失败了
			})
		}
	})
}

open-type="getPhoneNumber"是小程序提供的一个获取手机号的按钮,回调中返回手机号信息密文,回调函数getPhoneNumber中调用了小程序的wx.login()获取sessionKey后端缓存,然后再用它解密按钮回调返回的密文手机号,这时偶尔就会出现解密失败的问题。

这里就有一个获取sessionKey和获取密文手机号顺序的问题,因为按钮回调时是直接拿到了密文手机号,这时我们再调用wx.login()去获取sessionKey,就有可能出现拿到的密文是用一个老的sessionKey加密的,当再次获取sessionKey时,发现sessionKey失效了返回了一个新的sessionKey,导致加密sessionKey和我们后来获取到的并不是同一个。盲猜按钮回调获取手机号密码时,微信并没有校验sessionKey是否失效。。。

解决方案

看起来最直接的解决方案当然是在触发按钮回调之前就提前调用wx.login()获取当前最新的sessionKey,拿到后再去获取手机号密文。但是这个时机就不太好确定了,难道用户一进入登录页面就调用wx.login()吗,也比较奇怪,因为获取到的code也只有几分钟有效期,如何用户停留在登录页面几分钟再点击手机号一键登录,也会出现问题。

可能微信自己也意识到这里设计的不合理性,从基础库2.21.2开始,一键获取手机号的按钮进行了安全升级,不再返回手机号密文了:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/getPhoneNumber.html
https://www.chengpei.top/upload/weixin_login.png
这个升级带来两个好处:

  1. 不再需要获取sessionKey来解密手机号,从而避免部分开发者不小心将sessionKey传到前端导致安全问题
  2. 不再需要在按钮回调之前调用wx.login,避免这奇怪的交互顺序

所以如果是新开发小程序,这里最好使用新的一键获取手机号的方式,如果是老的小程序目前旧的方式也是可以继续使用的,并没有被下架,但是需要注意的还是sessionKey一定要避免返回到前端。

0

评论区