js混淆之webpack-obfuscator
混淆是什么
混淆是故意制造混淆代码的行为,即让人难以理解的源代码,类似于加密,但计算机能够识别理解代码并且执行它。混淆可以用来隐藏来自外部世界的业务逻辑,也可以实现压缩。
简单的原理:使用工具对JS进行一下AST(抽象语法树)分析、修改,再重新根据AST生成JS。
混淆的使用场景
1、第三方公司使用公司软件,使用这个插件可以保护源码,它会在源码中加入废代码段,字符编码转义使构建代码完全混淆,达到无法恢复源码甚至无法阅读的目的。
2、防止web攻击,很多web攻击都是通知直接debug业务逻辑找到漏洞进行攻击,通过进行代码混淆,源码达到无法阅读后,业务逻辑的代码就不会被破解。
混淆与压缩的区别
压缩:删除JavaScript代码中的注释、跳格符号、换行符号以及无用的空格,从而压缩JS文件大小,优化页面加载速度。
混淆:经过编码将变量和函数原命名改为毫无意义的命名,以防止他人窥视和窃取JavaScript源码,也有一定压缩效果。
举个例子…
上面代码经过webpack5自带的js压缩功能后生成的代码如下:
然后经过使用webpack-obfuscator插件混淆之后的代码如下:
从上面这个例子我们可以看出,经过使用混淆插件之后webpack打包生成的代码是跟源码不一样了的,它将源码编码成了我们难以阅读或者说是根本阅读不下去的代码,而且它也会对代码进行压缩,具有一定的压缩功能。
如何验证webpack-obfuscator对代码具有压缩功能?
可以将webpack的mode设置为development,当设置为开发模式的时候webpack对js的自动压缩功能(UglifyJS Webpack Plugin)就会被关闭,这个时候你再通过npm run build
打包项目,你会发现代码还是被压缩过的。
webpack-obfuscator插件使用与loader使用的场景
根据官网的提示我们可以知道,我们最好只混淆我们自己写的代码,向第三方插件库的代码是不建议混淆的,因为混淆后的代码要比原来的要慢15-80%,而且第三方插件的文件非常大。
webpack-obfuscator插件的使用场景
当你计划将代码和第三方代码拆分为不同的捆绑包时可以使用webpack-obfuscator插件的形式。
// webpack plugin配置
plugins: [
new JavaScriptObfuscator({
rotateStringArray: true
}, ['abc.js'])
]
webpack-obfuscator loader的使用场景
有时你需要输出单个js包,但仍需要混淆某个特定模块的源代码。在这些情况下,加载器可以做到这一点。在webpack配置中定义规则,并使用obfuscator-loader作为模块的最后一个加载器。你可以添加enforce: 'post'
标志以确保在正常加载器之后调用obfuscator-loader。
var WebpackObfuscator = require('webpack-obfuscator')
//...
// webpack 加载器配置
rules: [
{
test: /\.js$/,
exclude: [
path.resolve(__dirname, 'excluded_file_name.js')
],
enforce: 'post',
use: {
loader: WebpackObfuscator.loader,
options: {
rotateStringArray: true
}
}
}
]
主要配置项
{
// 压缩,无换行
compact: true,
// 是否启用控制流扁平化(降低1.5倍的运行速度)
controlFlowFlattening: false,
// 应用概率;在较大的代码库中,建议降低此值,因为大量的控制流转换可能会增加代码的大小并降低代码的速度。
controlFlowFlatteningThreshold: 0.75,
// 随机的死代码块(增加了混淆代码的大小)
deadCodeInjection: false,
// 死代码块的影响概率
deadCodeInjectionThreshold: 0.4,
// 此选项几乎不可能使用开发者工具的控制台选项卡
debugProtection: false,
// 如果选中,则会在“控制台”选项卡上使用间隔强制调试模式,从而更难使用“开发人员工具”的其他功能。
debugProtectionInterval: false,
// 通过用空函数替换它们来禁用console.log,console.info,console.error和console.warn。这使得调试 器的使用更加困难。
disableConsoleOutput: false,
//锁定混淆的源代码,使其仅在特定域和/或子域上运行。这使得某人只需复制并粘贴您的源代码并在其他地方运行就变得非常困难。
domainLock: [],
//标识符的混淆方式 hexadecimal(十六进制) mangled(短标识符)
identifierNamesGenerator: 'hexadecimal',
//全局标识符添加特定前缀,在混淆同一页面上加载的多个文件时使用此选项。此选项有助于避免这些文件的全局标识符之间发生冲突。为每个文件使用不同的前缀
identifiersPrefix: '',
inputFileName: '',
// 允许将信息记录到控制台。
log: false,
// 是否启用全局变量和函数名称的混淆
renameGlobals: false,
// 禁用模糊处理和生成标识符
reservedNames: [],
// 禁用字符串文字的转换
reservedStrings: [],
// 通过固定和随机(在代码混淆时生成)的位置移动数组。这使得将删除的字符串的顺序与其原始位置相匹配变得更加困难。如果原始源代码不小,建议使用此选项,因为辅助函数可以引起注意。
rotateStringArray: true,
// 混淆后的代码,不能使用代码美化,同时需要配置 cpmpat:true;
seed: 0,
selfDefending: false,
sourceMap: false,
sourceMapBaseUrl: '',
sourceMapFileName: '',
sourceMapMode: 'separate',
// 删除字符串文字并将它们放在一个特殊的数组中(多用于对密钥字符串的混淆)
stringArray: true,
// 编码的所有字符串文字stringArray使用base64或rc4并插入即用其解码回在运行时的特殊代码。 true(boolean):stringArray使用编码值base64;false(boolean):不编码stringArray值;'base64'(string):stringArray使用编码值base64;'rc4'(string):stringArray使用编码值rc4。大约慢30-50%base64,但更难获得初始值。建议禁用unicodeEscapeSequence带rc4编码的选项以防止非常大的混淆代码。
stringArrayEncoding: false,
// 调整字符串文字将插入stringArray的概率
stringArrayThreshold: 0.75,
// 您可以将混淆代码的目标环境设置为以下之一:Browser;Browser No Eval;Node
target: 'browser',
// 是否启用混淆对象键
transformObjectKeys: false,
// 允许启用/禁用字符串转换为unicode转义序列。Unicode转义序列大大增加了代码大小,并且可以轻松地将字符串恢复为原始视图。建议仅对小型源代码启用此选项。
unicodeEscapeSequence: false
}
使用的时候注意事项
安装 webpack-obfuscator
时要注意webpack-obfuscator
的版本要与本地项目 webpack
版本相匹配,如果不匹配会报错无法使用。以及webpack-obfuscator在不同版本下的使用方式也会有所差异,需要注意不同版本下的配置方式。每个webpack适配的webpack-obfuscator版本详情,可去webpack-obfuscator git官网的tags的package.json上进行详细查看。
下面是一些常见webpack版本的安装方式:
webpack5的安装方式
npm install --save-dev javascript-obfuscator webpack-obfuscator
webpack4的安装方式
npm install --save-dev javascript-obfuscator webpack-obfuscator@2.6
webpack3.4.1的安装方式
npm install --save-dev javascript-obfuscator@0.10.0 webpack-obfuscator@0.10.0
PS:webpack3.4.1使用webpack-obfuscator可能会报node版本太高的问题,需要降低node版本
如何验证混淆成功了
1、查看打包后的代码是否达到无法恢复源码甚至无法阅读的效果。
2、创建一个本地代理转发服务器,验证项目是否能正常运行,功能是否完整。