侧边栏壁纸
  • 累计撰写 47 篇文章
  • 累计创建 2 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

工程化:代码混淆的原理和实现

代码混淆是什么?

代码混淆(Code Obfuscation)是一种通过改变代码的结构和形式,使其难以被理解、分析和逆向工程,同时保持功能不变的技术。主要用于保护知识产权、防止逆向分析和恶意篡改。

原理
  1. 变量与函数名混淆
  • 将具有描述性的变量名和函数名替换为无意义的短字符(如 a、b、c)。

    // 原始代码
    function calculateTotal(price, quantity) {
        return price * quantity;
    }
    // 混淆后
    function a(b, c) {
        return b * c;
    }
    
  1. 字符串混淆
  • 对字符串进行编码或拆分成多个部分,运行时再还原。

  • 常见方法:Base64 编码、Unicode 转义、字符串分割拼接。

    // 原始代码
    console.log("Hello World");
    // 混淆后
    console.log("\x48\x65\x6c\x6c\x6f\x20\x57\x6f\x72\x6c\x64");
    
  1. 控制流扁平化
  • 将代码的逻辑结构(如 if​、for​等)转换为难以理解的 switch​或 while 结构,增加分析难度。
  • 例如,将简单的条件分支用 switch 和随机标签重组。
  1. 代码压缩与优化
  • 移除空白字符、注释、缩短局部变量名(通常通过工具如 UglifyJS​、Terser 实现)。
  • 这是基本的混淆和优化步骤,虽然可读性降低,但反混淆相对容易。
  1. 插入无效代码(Dead Code Injection)
  • 在代码中添加不会执行或没有实际作用的语句,干扰静态分析。
  • 例如:添加永不执行的条件分支、无意义的算术运算。
  1. 使用 JavaScript 混淆工具
  • UglifyJS/Terser: 主要用于压缩和优化,附带简单的变量名混淆。
  • JavaScript Obfuscator(例如 javascript-obfuscator): 提供高级混淆选项,如控制流扁平化、字符串编码、域名锁定等。
  • Closure Compiler: Google 的工具,可进行高级优化和重命名。
  1. 代码加密与运行时解密
  • 将部分核心代码加密,在运行时通过解密函数动态执行(例如使用 eval​或 Function 构造函数)。
  • 注意:eval 可能影响性能并带来安全风险,需谨慎使用。
  1. 混淆 HTML 和 CSS
  • HTML: 通过 JavaScript 动态生成 DOM 结构,或使用编码字符。
  • CSS: 缩短类名、使用属性选择器混淆,或将 CSS 嵌入 JavaScript 中动态注入。
  1. 防止调试
  • 检测开发者工具(如重写 console.log​、监听 F12 按键、检测代码执行时间差等),干扰调试过程。
  1. 使用 WebAssembly(Wasm)
  • 将关键算法或逻辑用 C/C++/Rust 编写,编译为 WebAssembly,以二进制格式执行,增加反编译难度。

在 Webpack 工程化项目中实现代码混淆,主要通过插件和配置来完成。以下是详细的实现方法和最佳实践:

  1. TerserWebpackPlugin
// webpack.config.js
const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
  mode: 'production',
  optimization: {
    minimize: true,
    minimizer: [
      new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true,    // 移除 console
            drop_debugger: true,   // 移除 debugger
            pure_funcs: ['console.log'] // 移除特定函数
          },
          mangle: {
            toplevel: true,        // 混淆顶层变量
            keep_classnames: false, // 不保留类名
            keep_fnames: false      // 不保留函数名
          },
          format: {
            comments: false         // 移除注释
          }
        },
        extractComments: false      // 不提取注释到单独文件
      })
    ]
  }
};
  1. JavaScript Obfuscator Plugin
// webpack.config.js
const JavaScriptObfuscator = require('webpack-obfuscator');

module.exports = {
  plugins: [
    new JavaScriptObfuscator({
      rotateStringArray: true,      // 字符串数组旋转
      stringArray: true,            // 字符串数组化
      stringArrayThreshold: 0.75,   // 字符串转换阈值
      splitStrings: true,           // 字符串拆分
      splitStringsChunkLength: 10,  // 拆分长度
      deadCodeInjection: true,      // 死代码注入
      deadCodeInjectionThreshold: 0.4,
      controlFlowFlattening: true,  // 控制流扁平化
      controlFlowFlatteningThreshold: 0.75,
      numbersToExpressions: true,   // 数字转表达式
      simplify: true,               // 简化代码
      selfDefending: true,          // 自我防御
      disableConsoleOutput: true,   // 禁用控制台输出
      debugProtection: true,        // 调试保护
      debugProtectionInterval: 4000 // 调试保护间隔
    }, 
    ['excluded_bundle_name.js'])    // 排除的文件
  ]
};

完整实现

// webpack.prod.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const JavaScriptObfuscator = require('webpack-obfuscator');

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    filename: '[name].[contenthash].js',
    path: path.resolve(__dirname, 'dist'),
  },
  devtool: false, // 生产环境关闭sourcemap或使用hidden-source-map
  
  optimization: {
    minimizer: [
      new TerserPlugin({
        parallel: true, // 多进程并行压缩
        terserOptions: {
          ecma: 2020,
          compress: {
            arguments: true,
            dead_code: true,
            drop_console: true,
            drop_debugger: true,
            comparisons: false,
            conditionals: true,
            evaluate: true,
            loops: true,
            booleans: true,
            unused: true,
            keep_fargs: false,
            keep_infinity: true,
            passes: 3
          },
          mangle: {
            safari10: true,
            properties: {
              regex: /^_/ // 不混淆下划线开头的属性
            }
          },
          format: {
            ascii_only: true,
            comments: /@license|@preserve/
          }
        }
      })
    ],
    splitChunks: {
      chunks: 'all'
    }
  },
  
  plugins: [
    // 按需使用混淆插件(注意:过度混淆可能影响性能)
    process.env.USE_OBFUSCATOR && new JavaScriptObfuscator({
      compact: true,
      controlFlowFlattening: false, // 启用会显著增加代码大小
      deadCodeInjection: false,     // 谨慎启用
      debugProtection: false,
      disableConsoleOutput: true,
      identifierNamesGenerator: 'hexadecimal',
      log: false,
      renameGlobals: false,
      rotateStringArray: true,
      selfDefending: true,
      shuffleStringArray: true,
      splitStrings: true,
      stringArray: true,
      stringArrayEncoding: ['rc4'],
      stringArrayThreshold: 0.75,
      unicodeEscapeSequence: false
    })
  ].filter(Boolean)
};
高级混淆策略

环境特定配置

// 通过环境变量控制混淆强度
const obfuscatorConfig = {
  low: { stringArray: false, renameGlobals: false },
  medium: { stringArray: true, renameGlobals: false },
  high: { stringArray: true, renameGlobals: true, controlFlowFlattening: true }
}[process.env.OBFUSCATION_LEVEL || 'medium'];

配合 Source Map(用于错误追踪)

{
  devtool: 'hidden-source-map', // 生成但不暴露sourcemap
  plugins: [
    new webpack.SourceMapDevToolPlugin({
      filename: '[file].map',
      append: false,
      moduleFilenameTemplate: '[absolute-resource-path]'
    })
  ]
}
CSS/HTML 资源混淆

CSS 压缩混淆

const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].[contenthash:8].css',
      chunkFilename: '[id].[contenthash:8].css'
    })
  ],
  optimization: {
    minimizer: [
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            'default',
            {
              discardComments: { removeAll: true },
              minifyFontValues: { removeQuotes: false }
            }
          ]
        }
      })
    ]
  }
};

HTML 压缩(Webpack 5)

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: isProduction ? {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true
      } : false
    })
  ]
};
注意事项

性能平衡:过度混淆会增加文件大小和执行时间
兼容性:某些混淆选项可能影响代码在低版本浏览器的运行
调试困难:混淆后错误堆栈难以阅读,需配合 Source Map
第三方库:避免混淆 node_modules 中的依赖
常量提取:敏感字符串仍可能被提取分析

const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html',
      minify: isProduction ? {
        removeComments: true,
        collapseWhitespace: true,
        removeRedundantAttributes: true,
        useShortDoctype: true,
        removeEmptyAttributes: true,
        removeStyleLinkTypeAttributes: true,
        keepClosingSlash: true,
        minifyJS: true,
        minifyCSS: true,
        minifyURLs: true
      } : false
    })
  ]
};


0

评论区