微信小程序session_key泄漏漏洞

一、背景

上篇文章介绍了微信小程序如何抓包,下面介绍一个常见的微信小程序严重漏洞(session_key泄漏漏洞)。为了保证数据安全,微信会对用户数据进行加密传输处理,所以小程序在获取微信侧提供的用户数据(如手机号)时,就需要进行相应的解密,这就会涉及到session_key,具体流程可参考开放数据校验与解密开发文档。session_key指的是会话密钥,可以简单理解为微信开放数据AES加密的密钥,它是微信服务器给开发者服务器颁发的身份凭证,这个数据正常来说是不能通过任何方式泄露出去的。小程序若存在session_key泄露漏洞的情况,则代表微信侧传递的用户数据有被泄露、篡改等风险,开发者应及时发现该漏洞并快速修复相应问题微信小程序session_key泄漏漏洞

二、漏洞案例

某小程序因为session_key泄露,导致该小程序可以使用任意手机号进行登录,造成了极大的安全风险。我们可以很明显地看到,下列请求中的session_key已经被泄露:微信小程序session_key泄漏漏洞

通过获取该session_key,我们可以结合iv解密出密文:

微信小程序session_key泄漏漏洞

只需如下脚本即可进行解密,所以攻击者也可利用同样的信息去篡改用户数据,然后加密后返回给服务器,从而达到使用任意手机号进行登录的目的。

微信小程序session_key泄漏漏洞

三、漏洞修复

通过上述案例,我们了解到session_key泄露会对小程序造成的危害,而导致session_key泄露的原因则可能有以下两种:

3.1 方式一

通过auth.code2Session接口获取用户openid时,返回小程序的数据中包含了session_key字段,以泄露的url:/api/get_openid.php?code=xxxx为例,具体的表现如下图所示:

微信小程序session_key泄漏漏洞

查看后端get_openid.php的源码,经排查发现$response 变量包含了session_key字段,开发者应去掉变量中的session_key字段,若需获取openid,应只提取该字段返回小程序即可。

3.2 方式二

在解密开放数据时,使用了错误的方式,以获取手机号接口为例,通过事件回调获取微信服务器返回的加密数据(encryptedData和iv)后,将服务端中的session_key传送至小程序前端,直接在前端进行解密:

微信小程序session_key泄漏漏洞

这种方式是绝对不可取的,正确的流程应该是将加密数据(encryptedData和iv)传至服务端后,结合服务端中的session_key进行解密获取手机号,然后返回给小程序。

四、拓展

小程序加密数据解密算法

接口如果涉及敏感数据(如wx.getUserInfo当中的 openId 和 unionId),接口的明文内容将不包含这些敏感数据。开发者如需要获取敏感数据,需要对接口返回的加密数据(encryptedData) 进行对称解密。解密算法如下:

  1. 对称解密使用的算法为 AES-128-CBC,数据采用PKCS#7填充。
  2. 对称解密的目标密文为 Base64_Decode(encryptedData)。
  3. 对称解密秘钥 aeskey = Base64_Decode(session_key), aeskey 是16字节。
  4. 对称解密算法初始向量 为Base64_Decode(iv),其中iv由数据接口返回。

示例代码

import base64
import json
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad


class WXBizDataCrypt:
    def __init__(self, appId, sessionKey):
        self.appId = appId
        self.sessionKey = sessionKey

    #  原始数据加密
    def encrypt(self, data, iv):
        sessionKey = base64.b64decode(self.sessionKey)
        iv = base64.b64decode(iv)
        cipher = AES.new(sessionKey, AES.MODE_CBC, iv)
        ciphertext = cipher.encrypt(pad(data.encode(), AES.block_size))
        return base64.b64encode(ciphertext)

    # encryptedData 解密
    def decrypt(self, encryptedData, iv):
        # base64 decode
        sessionKey = base64.b64decode(self.sessionKey)
        encryptedData = base64.b64decode(encryptedData)
        iv = base64.b64decode(iv)

        cipher = AES.new(sessionKey, AES.MODE_CBC, iv)
        decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)))

        if decrypted['watermark']['appid'] != self.appId:
            raise Exception('Invalid Buffer')

        return decrypted

    def _unpad(self, s):
        return s[:-ord(s[len(s)-1:])]


if __name__ == '__main__':
    appId = 'xxxxx'
    sessionKey = 'xxxxx'
    encryptedData = 'xxxxx'
    iv = 'xxxxx'
    pc = WXBizDataCrypt(appId, sessionKey)
    print(pc.decrypt(encryptedData, iv))

参考链接:

  • https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html
  • https://developers.weixin.qq.com/community/develop/doc/000806202400280b0edd5866156c01


原文始发于微信公众号(洋洋自语):微信小程序session_key泄漏漏洞

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/273098.html

(0)
明月予我的头像明月予我bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!