[TOC] #### 1. 前言 --- 很多开发者在发布项目时都有这样的顾虑:我的 JS 文件代码不想被别人知道,能不能加密 ? 其实,在浏览器端运行意味着代码必须对用户可见,严格意义上的加密并不可行,我们真正需要做的是代码压缩与混淆 #### 2. 混淆工具 --- 目前业界最强大、最流行的 JavaScript 混淆工具是 `javascript-obfuscator` 官网地址:<https://obfuscator.io>,它不仅能压缩代码,还能进行控制流平坦化、字符串加密、变量重命名等高级混淆 它支持 Node.js 环境、浏览器环境以及命令行使用,能够将代码转换为难以阅读和逆向工程的形式,同时保持功能不变 使用 npm 全局安装(命令行使用) ```bash npm install -g javascript-obfuscator ``` 安装成功后查看版本(我安装时,当前是版本号 5.3.0) ```bash # --version 可以使用缩略名 -v javascript-obfuscator --version ``` 命令格式: ```plaintext javascript-obfuscator [源文件] --output [混淆后输出的文件名] [混淆选项] ``` 执行混淆命令(基础使用) ```bash javascript-obfuscator input.js --output output.js ``` 混淆参数选项: + `--compact true`:启用代码紧凑模式(移除空格、换行符、注释,代码压缩为一行) + `--string-array true`:字符串数组转换(把字符串提取出来,放入数组,被替换为类似 `_0x1234[0x1]`) + `--string-array-encoding 'base64'`:对字符串数组中的值进行编码(运行时混淆器会自动解码回原始字符串) + `--string-array-threshold 1`:字符串转换的阈值,值是 0-1 之间的数字(表示移入字符串数组的比例) + `--control-flow-flattening true`:控制流扁平化,打乱代码执行顺序结构,使调试器难以跟踪 + `--control-flow-flattening-threshold 0.75`:控制流扁平化的阈值,值是 0-1 之间的数字 + `--config obfuscator-config.json`:指定外部配置文件路径,推荐用于复杂配置 ```plaintext javascript-obfuscator input.js --output output.min.js \ --compact true \ --string-array true \ --string-array-encoding 'base64' \ --string-array-threshold 1 \ --control-flow-flattening true \ --control-flow-flattening-threshold 0.75 ``` 上面只是列举部分混淆选项,其他选项根据项目需求来选择: + `--debug-protection true`:启用调试保护机制,强制让调试器陷入无限循环或极其缓慢 由于命令行参数众多,当混淆选项比较复杂时,为了方便查看和管理混淆选项,可以使用配置文件 ```json { "compact": true, "stringArray": true, "stringArrayEncoding": ["base64"], "stringArrayThreshold": 1, "controlFlowFlattening": true, "controlFlowFlatteningThreshold": 0.75 } ``` 运行命令指向配置文件,使用该配置文件中的混淆选项 ```bash javascript-obfuscator input.js --config obfuscator-config.json --output output.js ``` #### 3. 压缩工具 --- `terser` 是目前 JavaScript 生态中最主流的压缩工具,它是 `uglify-es` 的继任者,完美支持 ES6+ 语法 全局安装后,可以直接在命令行使用它来压缩代码、删除 `console.log`、移除 `debugger`语句以及混淆变量名 ```bash # 全局安装 npm install -g terser # 查看版本 terser --version ``` 基本语法格式: ```plaintext terser [输入文件] [选项] -o [输出文件] ``` 基础压缩(最常用) ```bash # 自动进行空格移除、变量重命名(混淆)、死代码消除 terser input.js -o output.js # 等价于 terser input.js --compress --mangle -o output.js ``` 使用 `--compress` 选项中的子配置,移除 `console.*` 调用,移除 `debugger;` 语句 ```bash terser input.js --compress drop_console=true,drop_debugger=true -o output.js ``` 也支持只删除特定的 `console` 类型,但是以下命令可能不生效,是因为参数传递格式在特定终端下被解析错误 ```bash # 删除 console.log,console.warn 语句 terser input.js --compress --pure-funcs "['console.log','console.warn']" -o output.js ``` 终极解决方案:使用配置文件(100% 成功) 在当前目录创建一个名为 `terser.config.json` 的文件,填入以下内容 ```json { "compress": { "pure_funcs": ["console.log", "console.warn"], "dead_code": true, "drop_console": false } } ``` *注意:`dead_code: true` 是默认值,但显式写上更保险* 运行命令指向该配置文件 ```bash terser input.js --config-file terser.config.json -o output.js ``` 所以,前面删除所有 `console` 和 `debugger` 的命令,也可以通过配置文件指定 ```json { "compress": { "dead_code": true, "drop_console": true, "drop_debugger": true } } ```