1. 背景与概念:
背景:小程序开发过程中的安全问题,如代码易被反编译,核心业务逻辑被破译,算法易被二次打包等,导致小程序存在被破解、核心代码被盗取的风险
总结:小程序加固就是:小程序提供给开发者对小程序前端代码进行加密的功能,以防止代码暴露
1.1 如何反编译小程序代码?
参考:
juejin.cn/post/720258… 【windows】
cloud.tencent.com/developer/a… 【mac反编译需要开启SIP】
1.在电脑端打开需要反编译小程序,尽可能多得浏览页面,
2.在微信配置的文件保存路径中找到当前小程序的wxapkg文件,通过对该文件解密可得到源码,
- 准备链接中的解密工具,输入解密指令完成解密【注意:解密路径中不要有空格】
- 执行反编译指令得到小程序源码。
2.加固过程:
加固参考: developers.weixin.qq.com/miniprogram…
- 在微信者开发者工具中右击实现对应文件加固。此时项目根目录下会生成 code_obfuscation_config.json 文件
{
"desc": "关于本文件的更多信息,请参考文档 代码加固开发者文档",
"switch": true, // 加固总开关,关闭则不执行加固流程
"configs": [
{
"path": "pages/index/index.js", // 加固文件的路径
"sub_switch": true // 加固子开关,该文件是否需要加固
}
]
}
2. 预览或者调试项目后会在根目录下生成对应的projectmaps,加固成功的可以通过编译结果打开查看
3.疑问总结:
3.1 加固范围如何确定
ps:加固的内容越多,对产品的性能影响可能越大,影响代码体积,需要综合考量 【developers.weixin.qq.com/community/d…
建议只加固小程序中的敏感数据信息、核心算法逻辑、关键执行路径、接口(签名算法、协议、密钥等)。界面操作和渲染、引用的第三方开源库等非必要安全保护内容可不进行加固,避免过多影响小程序体积及性能
现有版本内容,全量加固的前后,对各分包体积差异影响有多少?
【未加固总包大小:5216kb,主包:1899kb】 【加固后总包大小:5868kb,主包大小1915kb】
3.2 加固生成的projectmaps文件是否需要提交
不需要
3.3 当次加固后后序还需要进行加固不?【文件变动这种】
每次上传之前都会对本地的配置code_obfuscation_config.json中的文件进行加固
3.4 使用miniprogram-ci 进行小程序代码的上传,还可以进行小程序代码加固吗?
社区提问中
3.5 线上有js异常后,“加固”是否会对问题源码定位有影响?
社区提问官方,提到不会对源码定位有影响
4.实践效果:
(1)加固文件范围:对项目中所有的page页面路径下面的js代码进行加固
(2)准备生成code_obfuscation_config.json脚本obfuscation.js
【由于微信提供的插件不能批量添加加固的文件,手动多次操作太耗费时间,可以借助脚本协助生成我们所需的配置文件,脚本文件放置在项目的根目录下】
#! /usr/bin/env node
const fs = require('fs');
const path = require('path');
const chalk = require('chalk');
const argv = require('minimist')(process.argv.slice(2));
let defaultConfig = {
entry: './build_dist/pages', // 批量进行加固的文件路径
excludes: ['node_modules'], // 排除在外的文件目录
desc: '关于本文件的更多信息,请参考文档 代码加固开发者文档: <https://developers.weixin.qq.com/miniprogram/dev/devtools/code_obfuscation.html>', // code_obfuscation_config.json的描述配置desc
switch: true, // code_obfuscation_config.json的加固开关配置switch
relativeRoot: './build_dist' // 依据入口配置entry最终转换的成code_obfuscation_config.json中的相对路径
};
if (argv.C || argv.config) {
const config = require(`${process.cwd()}/${argv.C || argv.config}`);
defaultConfig = Object.assign(defaultConfig, config);
}
const obfuPaths = [];
function getJsPaths(dir) {
const dirents = fs.readdirSync(dir, { withFileTypes: true });
dirents.forEach((dirent) => {
const { name } = dirent;
if (defaultConfig.excludes.includes(name)) return;
const direntPath = path.join(dir, name);
if (dirent.isDirectory()) {
getJsPaths(direntPath);
}
if (/\.(js|JS)$/.test(name)) {
obfuPaths.push(path.relative(defaultConfig.relativeRoot, direntPath).replace(/\\/g, '/'));
}
});
}
getJsPaths(defaultConfig.entry);
const jsonData = {
desc: defaultConfig.desc,
switch: defaultConfig.switch,
configs: obfuPaths.map((obfuPath) => ({ path: obfuPath, sub_switch: true })),
};
try {
fs.writeFileSync('./code_obfuscation_config.json', JSON.stringify(jsonData, null, '\t'));
console.log(chalk.hex('#17C557')('code_obfuscation_config.json written success!'));
} catch (error) {
console.error(error);
}
脚本参数介绍
defaultConfig = {
entry: './src/pages', // 批量进行加固的文件路径
excludes: ['node_modules', 'demo'], // 排除在外的文件目录
desc: '关于本文件的更多信息,请参考文档 代码加固开发者文档', // code_obfuscation_config.json的描述配置desc
switch: true, // code_obfuscation_config.json的加固开关配置switch
relativeRoot: './src' // 依据入口配置entry最终转换的成code_obfuscation_config.json中的相对路径
};
(3)执行脚本: npm run obfuscate生成加固配置文件。并最后编译预览查看结果
(4)加固前后反编译对比
(5)现存问题:有十项未加固成功。有什么规律吗?demo文件夹【仅在本地有,.gitignore中已忽略,加固过程也可以过滤】,加固范围内文件夹下js有的可以 有的不行,找一找规律
实际执行加固(跑代码)是在哪个流程步骤中?会不会这几个未加固的文件是加固后才生成的?
实际执行加固插件是执行在"预览"/"真机调试"/"上传"几个流程前【跑脚本是生成加固的配置文件,配置在配置文件中的代码才会被加固加密】
接入miniprogram-ci的脚本js
const ci = require('miniprogram-ci')
;(async () => {
const project = new ci.Project({
appid: 'appid',
type: 'miniProgram',
projectPath: '/Users//build_dist',
privateKeyPath: 'privateKeyPath',
ignores: ['node_modules/**/*'],
})
const uploadResult = await ci.upload({
project,
version: '6.36.2',
desc: 'ci 加固代码提交',
setting: {
es6: true,
es7: true,
autoPrefixWXSS: true,
minifyWXSS: true,
minifyWXML: true,
minifyJS: true,
minify: true
},
onProgressUpdate: console.log,
})
console.log(uploadResult)
})()