【小程序】小程序加固

939 阅读5分钟

1. 背景与概念:

背景:小程序开发过程中的安全问题,如代码易被反编译,核心业务逻辑被破译,算法易被二次打包等,导致小程序存在被破解、核心代码被盗取的风险

总结:小程序加固就是:小程序提供给开发者对小程序前端代码进行加密的功能,以防止代码暴露

1.1 如何反编译小程序代码?


参考:

juejin.cn/post/720258… 【windows】

cloud.tencent.com/developer/a… 【mac反编译需要开启SIP】

1.在电脑端打开需要反编译小程序,尽可能多得浏览页面,

2.在微信配置的文件保存路径中找到当前小程序的wxapkg文件,通过对该文件解密可得到源码,

image.png

  1. 准备链接中的解密工具,输入解密指令完成解密【注意:解密路径中不要有空格】
  2. 执行反编译指令得到小程序源码。

image.png

2.加固过程:

加固参考: developers.weixin.qq.com/miniprogram…

image.png

  1. 在微信者开发者工具中右击实现对应文件加固。此时项目根目录下会生成 code_obfuscation_config.json 文件
{
    "desc": "关于本文件的更多信息,请参考文档 代码加固开发者文档",
    "switch": true, // 加固总开关,关闭则不执行加固流程
    "configs": [
    {
    "path": "pages/index/index.js", // 加固文件的路径
    "sub_switch": true // 加固子开关,该文件是否需要加固
    }
  ]
}

2. 预览或者调试项目后会在根目录下生成对应的projectmaps,加固成功的可以通过编译结果打开查看

image.png

3.疑问总结:

3.1 加固范围如何确定

ps:加固的内容越多,对产品的性能影响可能越大,影响代码体积,需要综合考量 【developers.weixin.qq.com/community/d…

建议只加固小程序中的敏感数据信息、核心算法逻辑、关键执行路径、接口(签名算法、协议、密钥等)。界面操作和渲染、引用的第三方开源库等非必要安全保护内容可不进行加固,避免过多影响小程序体积及性能

现有版本内容,全量加固的前后,对各分包体积差异影响有多少?

image.png

【未加固总包大小: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)
})()