快雪时晴-初晴融雪头像
Nuxt2:打包后dist文件下变量的值不要明文显示 / 以base64值显示 / 起到一定的保护作用 / 增加逆向阅读成本封面图

Nuxt2:打包后dist文件下变量的值不要明文显示 / 以base64值显示 / 起到一定的保护作用 / 增加逆向阅读成本

一、需求描述

前端项目 / nuxt2项目 打包后,变量值为明文,是没有混淆的内容,这个状态是对的,如果变量的值也混淆了,就失去代码的意义了,但是如何能在一定程度上“密文”显示呢 以增加逆向阅读成本。

二、开发实现梳理

feat(build): 在生产环境启用代码混淆保护

- 引入 webpack-obfuscator 插件

- 仅在生产环境启用代码字符串混淆和控制流扁平化

- 注入死代码以增加反调试难度

- 禁用 console 输出防止日志泄露

- 字符串数组启用 base64 编码和随机旋转

- 设置 75% 的字符串参与混淆处理

三、优缺点分析

用 webpack-obfuscator 对 api 这个单独的 js 文件做代码混淆(不是普通 Terser 压缩),可以控制:字符串加密、控制流平坦化、变量名乱码。

✅ 优点:逆向阅读成本很高,普通开发者打开混淆后的 js 看不懂;

❌ 缺点:

  1. 只会加密源码里的字符串,浏览器发出请求后,Network 面板依旧完整显示 url;
  2. 增加打包体积、页面解密耗时;
  3. 自动生成的 api 文件每次生成后都要参与混淆;

四、哪些内容会被混淆

会被混淆不会被混淆
变量名、函数名中文注释、文档字符串
字符串字面量(部分)正则表达式内容
控制流结构第三方库的固定文本
对象属性名(部分)国际化/多语言文本

五、webpack-obfuscator 完整配置参数

webpack-obfuscator 是 javascript-obfuscator 的 Webpack 封装,核心参数完全相同,额外增加 Webpack 特有选项

javascript-obfuscator 是核心混淆引擎(底层本体);
webpack-obfuscator 是它的 Webpack 适配器 / 插件,专门对接 Webpack 构建流程

包定位使用场景调用方式
javascript-obfuscatorJS 混淆核心库,独立工具Node 脚本、单独混淆 JS 文件、vite/rollup 等其他构建工具API:JavaScriptObfuscator.obfuscate(code, options),也支持 cli 命令行
webpack-obfuscatorWebpack Plugin + Loader 包装器Webpack 项目打包时自动混淆 chunk/js 模块在 webpack.config.js 的 plugins 里 new WebpackObfuscator (obfuscatorOptions, excludes)

5.1、核心混淆参数(继承自 javascript-obfuscator)

参数类型默认值说明
compactbooleantrue压缩代码
controlFlowFlatteningbooleanfalse控制流平坦化
controlFlowFlatteningThresholdnumber0.75控制流平坦化概率
deadCodeInjectionbooleanfalse注入死代码
deadCodeInjectionThresholdnumber0.4死代码注入概率
stringArraybooleantrue启用字符串数组
stringArrayThresholdnumber0.75字符串加密概率
stringArrayEncodingstring[][]编码:'base64', 'rc4'
identifierNamesGeneratorstring'hexadecimal'命名方式
renameGlobalsbooleanfalse混淆全局变量
debugProtectionbooleanfalse调试保护
selfDefendingbooleanfalse自我保护
disableConsoleOutputbooleanfalse禁用 console
domainLockstring[][]域名锁定
reservedNamesstring[][]保留标识符
reservedStringsstring[][]保留字符串

5.2、Webpack 特有参数

参数类型默认值说明
excludestring[][]排除不混淆的 chunk 文件名
includestring[][]只混淆指定的 chunk
sourceMapbooleanfalse是否生成 sourceMap
sourceMapModestring'separate'sourceMap 模式
sourceMapSourcesModestring'sources-content'sourceMap 来源

六、nuxt.config.js代码核心片段

项目环境:Nuxt2+Webpack4

// 安装依赖
yarn add -D webpack-obfuscator@2.6.0
yarn add -D javascript-obfuscator@2.19.1

obfuscator 的语义是"混淆器"
obfuscate(动词):使模糊、使晦涩难懂
obfuscator(名词):执行混淆操作的程序/工具
在代码安全领域,代码混淆器的作用是:
将可读的源代码转换为功能相同但难以阅读和理解的形式
增加逆向工程的难度
保护知识产权和商业逻辑
require('events').EventEmitter.defaultMaxListeners = 50
const path = require('path')

// 尝试加载 webpack-obfuscator,未安装时不影响打包
let WebpackObfuscator = null
try {
  WebpackObfuscator = require('webpack-obfuscator')
} catch (e) {
  console.warn('[webpack-obfuscator] 未安装,跳过代码混淆')
}

const {env} = process
const isProd = env.MODE === 'prod'
let envFileName = ''
if (['DEV', 'TEST', 'UAT', 'PRE', 'PRD'].indexOf(env.MODE) > -1) {
  require('dotenv').config({
    path: `.env.${env.MODE}`
  })
  envFileName = `.env.${env.MODE}`
} else {
  require('dotenv').config()
  envFileName = '.env'
}

const apiServer = process.env.API_SERVER
const {processenvabcdef} = process.env
if (!isProd) {
  console.log(
    `当前本地环境变量值: \n apiServer: ${apiServer}`
  )
} else {
  console.log(`当前线上环境变量值: \n 公共地址 : ${process.env.PUBLIC_PATH}`)
}

const config = {
  env: {
    '/abc-def/': processenvabcdef,
  },
}

let axios = {
  proxy: true,
}

// 如果生产指定apiServer, 则使用绝对路径请求api
if (isProd && apiServer) {
  axios = {
    proxy: false,
    baseURL: apiServer,
  }
}

module.exports = {
  // dir在前,srcDir在后
  dir: {
    assets: '../m-front-common/pc/assets',
    layouts: 'layouts',
    middleware: 'middleware',
    pages: 'pages',
    static: '../m-front-common/pc/static',
    store: 'store',
  },
  srcDir: 'src/',
  ssr: false,
  env: {
    COOKIE_PATH: process.env.COOKIE_PATH || '/',
  },
  proxy: config.env,
  router: {
    base: process.env.ROUTER_BASE,
    middleware: ['meta', 'auth'],
    mode: 'hash',
    extendRoutes(routes, resolve) {
      if (!(process.env.NODE_ENV === 'prodution') && process.argv.slice(2).includes('--list')) {
        require('./m-front-common/extendRoutes').extendRoutes(routes, resolve)
      }
    },
  },
  server: {
    port: 3001,
    host: 'localhost',
  },
  /*
   ** Build configuration
   */
  styleResources: {
    less: '../m-front-common/pc/assets/m-var.less',
  },
  build: {
    publicPath: process.env.PUBLIC_PATH,
    extractCSS: isProd,
    extend (config, {isDev}) {
      config.resolve.alias = config.resolve.alias || {}
      const {alias} = config.resolve
      alias['@api'] = path.join(__dirname, 'm-front-common/pc/api')
      alias.vue = path.join(__dirname, 'node_modules/vue')

      // 生产环境通过 loader 方式对 src 目录下的 JS 进行混淆(字符串 base64 加密)
      if (!isDev && WebpackObfuscator) {
        config.module.rules.push({
          test: /\.js$/,
          include: [ // 如果不包含范围就是所有文件
            path.resolve(__dirname, 'src'),
            path.resolve(__dirname, 'm-front-common/pc/api'),
            path.resolve(__dirname, 'm-front-common/pc/const'),
          ],
          exclude: /node_modules/, // 如果不排除范围就是所有文件
          enforce: 'post',
          use: {
            loader: WebpackObfuscator.loader,
            options: {
              stringArray: true,
              stringArrayEncoding: ['base64'],
              rotateStringArray: true,
              stringArrayThreshold: 1,
              // 关闭最耗时的选项,避免打包卡住
              controlFlowFlattening: false,
              deadCodeInjection: false,
              debugProtection: false,
              disableConsoleOutput: true,
            },
          },
        })
      } // WebpackObfuscator
    },
  },
  /*
   ** Headers of the page
   */
  head: {
    title: '',
    meta: [{
      charset: 'utf-8'
    },
    {
      name: 'viewport',
      content: 'width=device-width, initial-scale=1'
    },
    {
      'http-equiv': 'x-ua-compatible',
      content: 'IE=edge, chrome=1'
    },
    {
      hid: 'description',
      name: 'description',
      content: '',
    },
    ],
    script: [],
  },
  loading: {
    color: '#5D81F9',
  },
  css: [{
    src: '../m-front-common/pc/assets/m-reset.less',
    lang: 'less',
  },],
  plugins: [],
  modules: [],
  axios,
}

七、打包后实现预期

八、哪些需要保留

业务 JS 字符串 ✅ 已 base64 加密

业务 JS 变量名 ✅ 已压缩

.vue 的 <script> 部分 ✅ 已处理

webpack publicPath ❌ 不能混淆

外部 CDN URL ❌ 不能混淆

HTML/CSS 里的路径 ❌ 不能混淆

所以不能过度混淆,过度混淆项目就打不开了,如下图

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/snowball_li/article/details/169264753

文章来源转载

评论

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--