一、概况与实现目标

在Web前端开发中,随着H5应用复杂度的提升和商业价值的增加,代码保护变得越来越重要。本文介绍的脚本基于javascript-obfuscator库,旨在为H5应用的静态资源提供自动化混淆方案,主要实现以下目标:

  1. 对指定目录下的JavaScript文件进行批量混淆

  2. 保留关键框架文件(如vendor开头的文件)

  3. 自动跳过JSON等非代码文件

  4. 实现递归目录处理能力

二、核心实现原理

1. 通过npm安装(推荐)

npm install javascript-obfuscator@4.1.1 --save-dev

2. 手动修改package.json

{
  "devDependencies": {
    "javascript-obfuscator": "^4.1.1"
  }

 注意:修改完之后 npm i 一下

3. 在package.json同级目录下创建一个js文件(obfuscate.js),文件取名随意

 4.完整代码(obfuscate.js内容)

代码中有不懂的配置,请自行网上查询

import fs from 'fs'
import path from 'path'
import jo from 'javascript-obfuscator'
import { fileURLToPath } from 'url'

// 获取当前文件的路径(URL形式),然后转换为文件路径
const __filename = fileURLToPath(import.meta.url)
// 从__filename中获取__dirname
const __dirname = path.dirname(__filename)

// 主要针对h5/assets目录下的资源文件进行处理(这里改成你打包输出的目录)
const outputDir1 = path.join(__dirname, 'h5') // 目标目录
const outputDir2 = path.join(outputDir1, 'assets') // 目标目录

// 定义要排除的前缀
const excludedPrefixes = ['vendor']

// 配置混淆器
const obfuscatorConfig = {
  compact: true,
  controlFlowFlattening: false,
  deadCodeInjection: false,
  debugProtection: false,
  debugProtectionInterval: 0,
  disableConsoleOutput: true,
  identifierNamesGenerator: 'hexadecimal',
  log: false,
  numbersToExpressions: false,
  renameGlobals: false,
  selfDefending: true,
  simplify: true,
  splitStrings: false,
  stringArray: true,
  stringArrayCallsTransform: false,
  stringArrayEncoding: [],
  stringArrayIndexShift: true,
  stringArrayRotate: true,
  stringArrayShuffle: true,
  stringArrayWrappersCount: 1,
  stringArrayWrappersChainedCalls: true,
  stringArrayWrappersParametersMaxCount: 2,
  stringArrayWrappersType: 'variable',
  stringArrayThreshold: 0.75,
  unicodeEscapeSequence: false,
  rotateStringArray: true,
  shuffleStringArray: true,
}

/**
 * 查找指定目录下的所有JS文件
 * @param {string} dirPath 目录路径
 * @returns {Promise<Array<{ path: string }>>} 返回所有JS文件的路径
 */
async function findScriptsInDir(dirPath) {
  const scripts = []
  const files = fs.readdirSync(dirPath, {
    encoding: 'utf8',
    withFileTypes: true,
  })

  for (const file of files) {
    const filePath = path.join(dirPath, file.name)

    if (file.isDirectory()) {
      scripts.push(...(await findScriptsInDir(filePath)))
    } else if (
      file.name.endsWith('.js') &&
      !excludedPrefixes.some((prefix) => file.name.startsWith(prefix))
    ) {
      scripts.push({ path: filePath })
    }
  }

  return scripts
}

/**
 * 混淆单个脚本文件
 * @param {string} filePath 文件路径
 * @returns {Promise<void>}
 */
async function obfuscateScript(filePath) {
  try {
    const data = fs.readFileSync(filePath, { encoding: 'utf8' })

    // 检查是否为JSON文件
    if (!isJson(data)) {
      const result = jo.obfuscate(data, obfuscatorConfig)
      const obfuscatedCode = result.getObfuscatedCode()
      fs.writeFileSync(filePath, obfuscatedCode)
      console.log(`Obfuscated: ${filePath}`)
    }
  } catch (error) {
    console.error(`Error obfuscating ${filePath}:`, error)
    throw error
  }
}

/**
 * 检查字符串是否为有效的JSON
 * @param {string} str 要检查的字符串
 * @returns {boolean}
 */
function isJson(str) {
  try {
    JSON.parse(str)
    return true
  } catch (error) {
    return false
  }
}

/**
 * 主函数,执行混淆操作
 */
async function main() {
  try {
    const scripts = await findScriptsInDir(outputDir2)
    console.log(`Found ${scripts.length} scripts to obfuscate.`)

    for (let i = 0; i < scripts.length; i++) {
      await obfuscateScript(scripts[i].path)
      console.log(`Progress: ${i + 1}/${scripts.length}`)
    }

    console.log('Obfuscation completed successfully.')
  } catch (error) {
    console.error('Obfuscation failed:', error)
  }
}

// 启动混淆过程
main()

5. 在package.json文件中 

"build": "vite build" 改成 "build": "vite build && node obfuscate.js" 在构建Vite项目后,立即对生成的JS代码进行混淆处理执行obfuscate.js

该混淆方案兼顾了保护强度与可维护性,实际测试表明能有效防范常规逆向分析。建议开发者依据项目需求灵活调整参数配置,并构建"混淆-测试-监控"的全流程保护机制。值得注意的是,代码保护是一个持续优化过程,需结合法律手段与技术升级来构筑全方位的安全防护体系。

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐