微信小程序已成为移动互联网主流应用形态之一,大量政务、教育、生活服务类业务均依托小程序落地。但在安全测试与代码审计过程中发现,前端代码硬编码云密钥、内网接口、敏感令牌等问题屡见不鲜,极易引发数据泄露、未授权访问等高风险漏洞。
传统小程序漏洞挖掘依赖人工提取缓存包、手动反编译、逐文件检索敏感信息,效率极低,单日仅能完成少量小程序检测。本文将搭建一套全自动化挖洞流水线 ,整合「缓存包提取、批量反编译、正则敏感扫描、云凭证验证、报告生成」五大环节,实现无人值守批量检测,大幅提升安全审计与漏洞挖掘效率。本文所有技术仅适用于自有小程序或获得正式授权的安全测试场景。
一、前期环境准备
整套流水线基于 Python + unveilr 反编译工具实现,跨 Windows、Linux、macOS 平台,以下为必备环境与依赖安装:
1. 基础环境
- Python 3.7 及以上版本(建议 3.9+);
- Node.js 12.0 及以上版本(
unveilr依赖运行环境); - PC 端微信(用于加载小程序,生成本地缓存包)。
2. 工具安装
(1)小程序反编译工具 unveilr
unveilr 是一款轻量化命令行反编译工具,支持小程序主包、子包批量解析,兼容性优于传统反编译工具,安装方式有两种:
- 方式 1:npm 全局安装(推荐)
bash
运行
npm i unveilr -g
- 方式 2:下载对应系统二进制可执行文件,配置系统环境变量后直接调用。
验证安装:命令行输入 unveilr -h,出现帮助信息即代表安装成功。
(2)Python 第三方依赖库
脚本需要调用阿里云 SDK 完成密钥验证,执行以下命令批量安装依赖:
bash
运行
pip install oss2 boto3 alibabacloud-sts20150401
二、第一步:批量提取微信本地 wxapkg 缓存包
微信小程序运行后,会将二进制包文件 wxapkg 缓存至 PC 本地目录,这也是我们逆向分析的数据源。
1. 缓存目录说明
Windows 系统默认缓存路径:
plaintext
C:\Users\你的用户名\Documents\WeChat Files\你的微信ID\Applet\
该目录下所有文件夹均以小程序 AppID 命名,每个文件夹内存放对应小程序的 wxapkg 包文件。微信会定期自动清理缓存,测试前需手动打开一批目标小程序,确保缓存加载完成。
2. Python 自动化提取脚本
手动遍历目录提取文件效率低下,通过 Python 遍历目录、批量复制并按 AppID 归档所有 wxapkg 文件:
python
运行
import os
import shutil
# 微信小程序缓存根目录(修改为你本地实际路径)
wechat_dir = r"C:\Users\admin\Documents\WeChat Files\wxid_xxx\Applet"
# 提取后的wxapkg输出目录
output_dir = r"D:\wxapkg_output"
# 创建输出目录(目录不存在则新建)
os.makedirs(output_dir, exist_ok=True)
# 递归遍历缓存目录
for root, dirs, files in os.walk(wechat_dir):
for file in files:
# 筛选wxapkg格式文件
if file.endswith('.wxapkg'):
# 获取小程序AppID作为文件名
appid = os.path.basename(root)
src_path = os.path.join(root, file)
dst_path = os.path.join(output_dir, f"{appid}.wxapkg")
# 复制文件并归档
shutil.copy2(src_path, dst_path)
print(f"成功提取小程序包:{appid}")
运行脚本后,所有缓存中的小程序包会统一归集到 D:\wxapkg_output 目录,便于后续批量反编译。
⚠️ 合规提醒:仅可提取自身开发 或获得书面授权的小程序缓存包,未授权提取、逆向他人小程序涉嫌违反《网络安全法》等相关法规。
三、第二步:unveilr 批量反编译 wxapkg
提取完成后,使用 unveilr 对整个目录下的小程序包进行批量反编译,一键生成结构化源码(JS、WXML、WXSS、JSON)。
1. 核心反编译命令
命令行执行以下指令,支持目录级批量反编译:
bash
运行
# -i 指定wxapkg输入目录 -o 指定源码输出目录
unveilr -i D:\wxapkg_output -o D:\decompiled
-i:必填参数,指向第一步提取的wxapkg存放目录;-o:必填参数,反编译后源码的输出目录。
2. 反编译结果说明
反编译完成后,D:\decompiled 目录下会按小程序生成独立文件夹,内部包含完整前端源码。其中 JS 文件 是敏感信息(密钥、接口、IP)的主要藏匿位置,也是后续扫描的核心目标。
四、第三步:正则表达式批量扫描敏感信息
反编译后的 JS 文件数量庞大,人工逐行检索几乎不现实。我们基于正则表达式编写扫描脚本,自动匹配业界高频出现的敏感数据:阿里云 AK/SK、OSS 地址、业务 API 接口、内网 IP、JWT 令牌等。
1. 敏感信息匹配规则设计
结合常见泄露特征,定义多组正则规则:
AccessKey/AKID:阿里云身份密钥,长度通常 16 位及以上;SecretKey/secret:阿里云私密密钥,长度普遍 30 位及以上;OSS_URL:阿里云对象存储地址;API_Endpoint:公网业务接口、管理后台接口;Internal_IP:内网 IP(10 段、172.16~172.31 段、192.168 段);JWT_Token:身份认证令牌。
2. 完整正则扫描脚本
python
运行
import os
import re
# 定义各类敏感信息正则规则
patterns = {
"AccessKey": r"(?i)(accessKeyId|accessKey|AKID)[\s]*[:=][\s]*['\"]?([A-Za-z0-9]{16,})['\"]?",
"SecretKey": r"(?i)(secretAccessKey|secretKey|secret)[\s]*[:=][\s]*['\"]?([A-Za-z0-9/+=]{30,})['\"]?",
"OSS_URL": r"(?:http|https)://[a-zA-Z0-9.-]+\.oss-[a-z]+\.aliyuncs\.com",
"API_Endpoint": r"(?:https?://)(?:api|open|gw|admin|internal)\.[a-zA-Z0-9.-]+\.(?:com|cn|net)",
"Internal_IP": r"\b(10\.\d{1,3}\.\d{1,3}\.\d{1,3}|172\.(?:1[6-9]|2\d|3[01])\.\d{1,3}\.\d{1,3}|192\.168\.\d{1,3}\.\d{1,3})\b",
"JWT_Token": r"eyJ[a-zA-Z0-9_-]{5,}\.[a-zA-Z0-9_-]{5,}\.[a-zA-Z0-9_-]{5,}"
}
# 存储扫描结果:{文件路径: {敏感类型: 匹配内容}}
scan_results = {}
# 递归遍历反编译后的源码目录
source_dir = r"D:\decompiled"
for root, dirs, files in os.walk(source_dir):
for file in files:
# 仅扫描JS文件
if file.endswith('.js'):
file_path = os.path.join(root, file)
# 读取文件内容,忽略编码异常
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
content = f.read()
# 逐个正则规则匹配
for p_type, regex in patterns.items():
match_list = re.findall(regex, content)
if match_list:
if file_path not in scan_results:
scan_results[file_path] = {}
scan_results[file_path][p_type] = match_list
# 格式化输出扫描结果
for file_path, findings in scan_results.items():
print(f"\n【扫描文件】{file_path}")
for p_type, content_list in findings.items():
print(f" 【{p_type}】")
# 仅展示前3条结果,避免输出冗余
for item in content_list[:3]:
print(f" {item}")
运行脚本后,程序会自动输出所有命中的敏感内容、对应文件路径,快速定位风险点。
五、第四步:云凭证(AK/SK)有效性批量验证
正则扫描得到的 AK/SK 可能是废弃密钥、测试密钥或权限受限密钥,需要进一步验证密钥有效性、账号归属、权限范围,区分真实高危漏洞与无效干扰项。
本节基于阿里云官方 Python SDK 编写验证脚本,调用 STS 身份接口、OSS 存储接口、ECS 接口综合检测密钥权限阿里云帮助中心。
1. AK/SK 验证脚本
python
运行
import oss2
import boto3
from alibabacloud_sts20150401.client import Client as StsClient
from alibabacloud_tea_openapi import models as open_api_models
def check_aliyun_ak(ak, sk):
"""
验证阿里云AK/SK有效性及权限
:param ak: AccessKeyId
:param sk: AccessKeySecret
"""
try:
# 初始化SDK配置
config = open_api_models.Config(
access_key_id=ak,
access_key_secret=sk
)
config.endpoint = 'sts.cn-hangzhou.aliyuncs.com'
sts_client = StsClient(config)
# 调用STS接口验证密钥有效性,获取账号ID
resp = sts_client.get_caller_identity()
account_id = resp.body.account_id
print(f"[有效密钥] AK前缀:{ak[:8]}... 所属账号ID:{account_id}")
# 遍历当前账号下所有OSS Bucket,检测存储权限
oss_auth = oss2.Auth(ak, sk)
oss_service = oss2.Service(oss_auth, 'oss-cn-hangzhou.aliyuncs.com')
print(" 关联OSS存储桶列表:")
for bucket in oss2.BucketIterator(oss_service):
print(f" - {bucket.name}")
# 检测ECS资源访问权限
ecs_client = boto3.client('ecs', region_name='cn-hangzhou',
aws_access_key_id=ak, aws_secret_access_key=sk)
ecs_instances = ecs_client.describe_instances()
for res in ecs_instances['Reservations']:
for ins in res['Instances']:
print(f" 关联ECS实例:{ins['InstanceId']} 公网IP:{ins['PublicIpAddress']}")
except Exception as e:
err_msg = str(e)
if "InvalidAccessKeyId" in err_msg or "Forbidden" in err_msg:
print(f"[无效/无权限密钥] AK前缀:{ak[:8]}...")
else:
print(f"[检测异常] 错误信息:{err_msg[:50]}")
# 调用示例(从扫描结果中提取AK、SK循环调用)
if __name__ == "__main__":
# 替换为扫描得到的AK/SK
test_ak = "你的AccessKey"
test_sk = "你的SecretKey"
check_aliyun_ak(test_ak, test_sk)
2. 结果解读
- 有效高权限密钥 :可正常列出 OSS 桶、ECS 实例,通常对应
AliyunOSSFullAccess等全域权限,属于严重漏洞; - 只读权限密钥:无法写入数据,但可读取桶内所有文件,依然会造成用户隐私泄露;
- 无效密钥 :提示
InvalidAccessKeyId,属于历史废弃密钥,无风险。
六、第五步:全流程自动化整合与定时任务
将「提取包、反编译、扫描、验证、报告生成」串联为一体化脚本,搭配系统定时任务,实现夜间自动运行,次日查看报告,真正做到无人值守。
1. 全流程主脚本框架
python
运行
import subprocess
import os
# 全局路径配置(根据本地环境修改)
WECHAT_CACHE = r"C:\Users\admin\Documents\WeChat Files\wxid_xxx\Applet"
WXAPKG_OUTPUT = r"D:\wxapkg_output"
DECOMPILED_DIR = r"D:\decompiled"
REPORT_PATH = r"D:\security_report.md"
# 导入前文子函数(提取、扫描、验证、报告生成)
from extract_wxapkg import extract_wxapkg
from scan_sensitive import scan_sensitive
from verify_ak import verify_credentials
from generate_report import generate_report
def main():
print("[1/5] 开始批量提取wxapkg缓存包...")
extract_wxapkg(WECHAT_CACHE, WXAPKG_OUTPUT)
print("[2/5] 开始批量反编译小程序包...")
subprocess.run(['unveilr', '-i', WXAPKG_OUTPUT, '-o', DECOMPILED_DIR])
print("[3/5] 开始扫描代码中的敏感信息...")
sensitive_data = scan_sensitive(DECOMPILED_DIR)
print("[4/5] 开始验证云凭证有效性...")
verify_credentials(sensitive_data)
print("[5/5] 生成Markdown检测报告...")
generate_report(sensitive_data, REPORT_PATH)
print("[+] 全流程检测完成!报告已输出至:", REPORT_PATH)
if __name__ == "__main__":
main()
2. 定时任务配置
- Windows:使用「任务计划程序」,设置每日凌晨自动执行该 Python 脚本;
- Linux/macOS:使用
crontab配置定时任务,实现周期性批量检测。
该模式下,单套流水线一晚可完成上百个小程序检测,效率远超人工。
七、实战漏洞场景分析
结合实际安全测试案例,小程序前端泄露主要分为两类高危场景:
场景 1:政务类小程序云密钥泄露
对智慧城市相关小程序测试时,脚本扫描在 config.js 中捕获硬编码阿里云 AK/SK。验证后发现,该密钥拥有全市政务类 OSS 存储桶完全读写权限,桶内包含交通卡口影像、公积金申请材料、居民证件扫描件等海量敏感数据,属于严重数据泄露漏洞。
场景 2:教育类小程序内网接口暴露
部分教育小程序源码中直接暴露未鉴权的内网管理接口(如 http://10.23.45.67:8080/admin/api)。该接口为测试环境教师管理后台,无身份校验、无访问白名单,攻击者可直接调用接口篡改学生成绩、查询学籍信息,构成高危未授权访问漏洞。
八、安全防御方案(开发者必看)
针对流水线挖掘出的高频漏洞,从开发规范、架构设计两方面给出防御建议,从源头规避风险:
1. 客户端代码规范
- 严禁硬编码密钥:云服务 AK/SK、数据库密码、令牌等敏感数据绝对不能写入小程序前端代码;
- 使用临时凭证 :阿里云、腾讯云等平台优先采用 STS 临时凭证、RAM 子账号,遵循最小权限原则分配权限,即使凭证泄露也能缩小影响范围。
2. 接口与网络架构防护
- 隐藏内网地址:禁止将内网 IP、内网接口直接暴露在前端,所有请求统一经过公网 API 网关转发;
- 全链路鉴权:管理类、数据类接口必须增加 Token 校验、IP 白名单、权限分级,杜绝未授权访问;
- 缓存管控:小程序后端增加代码加固,降低被逆向分析后漏洞利用的成功率。
3. 企业安全自检建议
企业可部署本文自动化流水线,定期对旗下小程序做内部安全审计,提前发现代码泄露问题,将风险扼杀在上线前。
九、重要合规声明
- 本文所有技术、脚本、工具仅用于个人学习、企业内部安全自查、已获得书面授权的渗透测试;
- 未经目标主体授权,擅自提取小程序缓存包、反编译、漏洞探测、漏洞利用,均属于违法行为;
- 网络安全技术应当坚守法律底线,做到技术向善。
总结
微信小程序前端代码泄露是长期存在的安全短板,传统人工挖洞模式早已无法适配批量审计的需求。本文搭建的自动化流水线,将繁琐的手工操作全部标准化、脚本化,实现了从「被动挖洞」到「主动批量审计」的转变。
对于安全从业者,这套流水线可大幅提升 SRC 漏洞挖掘、企业安全测试的效率;对于开发人员,通过本文暴露的漏洞场景与防御方案,可优化代码规范与架构设计,减少线上安全风险。安全防护从来不是单一环节的工作,只有开发、测试、运维协同发力,才能构建完整的小程序安全体系。