使用webpack-obfuscator進(jìn)行代碼混淆及報錯解決過程
背景
隨著前端技術(shù)的發(fā)展,特別是單頁應(yīng)用(SPA)的普及,越來越多的應(yīng)用邏輯和業(yè)務(wù)代碼暴露在客戶端瀏覽器中運行。
這使得應(yīng)用代碼容易被查看、復(fù)制甚至修改,從而可能引發(fā)安全問題或商業(yè)機(jī)密泄露。
可以通過瀏覽器控制臺查看頁面源碼, 如下圖:

webpack-obfuscator 介紹
webpack-obfuscator 是一個用于混淆 Webpack 打包后的 JavaScript 代碼的插件。它通過對代碼進(jìn)行混淆處理,使原始代碼變得難以閱讀和理解,從而保護(hù)代碼的知識產(chǎn)權(quán)和業(yè)務(wù)邏輯。
這種混淆通常包括變量重命名、字符串加密、控制流扁平化等技術(shù)手段。webpack-obfuscator 可以在構(gòu)建過程中對 JavaScript 代碼進(jìn)行混淆,使其在部署到生產(chǎn)環(huán)境時更加安全。
安裝
npm install webpack-obfuscator@2.6.0 javascript-obfuscator@3.2.7 --save-dev # 或者 yarn add webpack-obfuscator@2.6.0 javascript-obfuscator@3.2.7 --dev
注意: 上面安裝的版本對應(yīng)的 webpack 4.47.0版本, 如果是 webpack 是低版本,對應(yīng)的插件版本也要降低
參數(shù)解析
混淆選項 (options)
compact (boolean): 是否壓縮輸出的代碼,默認(rèn)為true。controlFlowFlattening (boolean): 是否啟用控制流扁平化,默認(rèn)為false。controlFlowFlatteningThreshold (number): 控制流扁平化的閾值,默認(rèn)為 0.75。deadCodeInjection (boolean): 是否注入死代碼,默認(rèn)為false。deadCodeInjectionThreshold (number): 死代碼注入的閾值,默認(rèn)為 0.4。debugProtection (boolean): 是否啟用調(diào)試保護(hù),默認(rèn)為 false。debugProtectionInterval (boolean): 是否啟用調(diào)試保護(hù)間隔,默認(rèn)為 false。domainLock (Array<string>): 鎖定指定的域名,默認(rèn)為空數(shù)組。identifierNamesGenerator (string): 生成標(biāo)識符名稱的方式,默認(rèn)為'mangled'。log (boolean): 是否記錄混淆過程,默認(rèn)為false。numbersToExpressions (boolean): 是否將數(shù)字轉(zhuǎn)換為表達(dá)式,默認(rèn)為false。renameGlobals (boolean): 是否重命名全局變量,默認(rèn)為false。rotateStringArray (boolean): 是否啟用字符串?dāng)?shù)組旋轉(zhuǎn),默認(rèn)為false。selfDefending (boolean): 是否啟用自我防御,默認(rèn)為false。simplify (boolean): 是否簡化輸出代碼,默認(rèn)為true。sourceMap (boolean | string): 是否生成源映射,默認(rèn)為false。sourceMapMode (string): 源映射模式,默認(rèn)為'separate'。splitStrings (boolean): 是否將字符串分割成多個較小的字符串,默認(rèn)為false。stringArrayEncoding (Array<string>): 字符串?dāng)?shù)組編碼方式,默認(rèn)為空數(shù)組。stringArrayEncodingThreshold (number): 字符串?dāng)?shù)組編碼的閾值,默認(rèn)為 0.75。stringArrayThreshold (number): 字符串?dāng)?shù)組閾值,默認(rèn)為 0.75。stringArrayWrappersCount (number): 字符串?dāng)?shù)組包裝器的數(shù)量,默認(rèn)為 2。stringArrayWrappersChainedCalls (number): 字符串?dāng)?shù)組包裝器鏈?zhǔn)秸{(diào)用的數(shù)量,默認(rèn)為 2。stringArrayWrappersParametersMaxCount (number): 字符串?dāng)?shù)組包裝器參數(shù)的最大數(shù)量,默認(rèn)為 2。stringArrayWrappersParametersMinCount (number): 字符串?dāng)?shù)組包裝器參數(shù)的最小數(shù)量,默認(rèn)為 1。stringArrayWrappersType (string): 字符串?dāng)?shù)組包裝器的類型,默認(rèn)為 ‘variable’。stringArrayWrappersVarNames (Array<string>): 字符串?dāng)?shù)組包裝器變量名稱,默認(rèn)為空數(shù)組。stringArrayIndexShift (boolean): 是否對字符串?dāng)?shù)組索引進(jìn)行偏移,默認(rèn)為false。shuffleStringArray (boolean): 是否打亂字符串?dāng)?shù)組,默認(rèn)為false。transformObjectKeys (boolean): 是否轉(zhuǎn)換對象鍵,默認(rèn)為false。transformObjectKeysBlackList (Array<string>): 不轉(zhuǎn)換的對象鍵黑名單,默認(rèn)為空數(shù)組。transformObjectKeysRecursive (boolean): 是否遞歸轉(zhuǎn)換對象鍵,默認(rèn)為false。transformObjectKeysWhitelist (Array<string>): 轉(zhuǎn)換的對象鍵白名單,默認(rèn)為空數(shù)組。unicodeEscapeSequence (boolean): 是否使用 Unicode 逃逸序列,默認(rèn)為false。useStrictSemicolons (boolean): 是否使用嚴(yán)格的分號,默認(rèn)為false。wrapCode (boolean): 是否包裹代碼,默認(rèn)為false。wrapComments (boolean): 是否包裹注釋,默認(rèn)為false。
排除選項 (exclude)
exclude (Array<string> | RegExp): 排除不需要混淆的模塊或文件。
請注意,上述配置示例包含了所有可用的參數(shù),但在實際項目中,你可能只需要設(shè)置其中的一部分。
強(qiáng)烈建議根據(jù)項目需求調(diào)整這些選項,以達(dá)到最佳的混淆效果并保持代碼的可維護(hù)性和性能。
配置示例
接下來,在你的 webpack.config.js 文件中配置 webpack-obfuscator 插件。
以下是一個簡單的示例配置:
const path = require("path");
const TerserPlugin = require("terser-webpack-plugin");
const WebpackObfuscator = require('webpack-obfuscator');
module.exports = {
configureWebpack: (config) => {
config.resolve = {
...config.resolve,
alias: {
"@": resolve("src"),
}
},
config.optimization = {
...config.minimizer,
minimizer: [
new TerserPlugin({
terserOptions: {
compress: {
drop_console: true,
},
},
}),
]
}
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
new WebpackObfuscator({
// 壓縮代碼
compact: true,
// 是否啟用控制流扁平化(降低1.5倍的運行速度)
controlFlowFlattening: false,
// 隨機(jī)的死代碼塊(增加了混淆代碼的大小)
deadCodeInjection: false,
// 此選項幾乎不可能使用開發(fā)者工具的控制臺選項卡
debugProtection: false,
// 如果選中,則會在“控制臺”選項卡上使用間隔強(qiáng)制調(diào)試模式,從而更難使用“開發(fā)人員工具”的其他功能。
debugProtectionInterval: false,
// 通過用空函數(shù)替換它們來禁用console.log,console.info,console.error和console.warn。這使得調(diào)試器的使用更加困難。
disableConsoleOutput: true,
// 標(biāo)識符的混淆方式 hexadecimal(十六進(jìn)制) mangled(短標(biāo)識符)
identifierNamesGenerator: 'hexadecimal',
log: false,
// 是否啟用全局變量和函數(shù)名稱的混淆
renameGlobals: false,
// 通過固定和隨機(jī)(在代碼混淆時生成)的位置移動數(shù)組。這使得將刪除的字符串的順序與其原始位置相匹配變得更加困難。如果原始源代碼不小,建議使用此選項,因為輔助函數(shù)可以引起注意。
rotateStringArray: true,
// 混淆后的代碼,不能使用代碼美化,同時需要配置 cpmpat:true;
selfDefending: true,
// 刪除字符串文字并將它們放在一個特殊的數(shù)組中
stringArray: true,
rotateUnicodeArray: true,
// stringArrayEncoding: 'base64',
stringArrayEncoding: ['base64'],
stringArrayThreshold: 0.75,
// 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對小型源代碼啟用此選項。
unicodeEscapeSequence: false,
// 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對小型源代碼啟用此選項。
transformObjectKeys: true,
// 排除選項
exclude: [/node_modules/, /\.min\.js$/]
})
)
}
},
}代碼混淆后

運行 npm run dev 報錯 Error: The number of constructor arguments in the derived class t must be >= than the number of constructor arguments of its base class.

上述報錯說明項目的 webpack 版本對應(yīng)的 webpack-obfuscator 和 javascript-obfuscator 版本過低導(dǎo)致報錯
運行 npm run dev 報錯 TypeError: Cannot read property ‘tap’ of undefined

上述報錯說明項目的 webpack 版本對應(yīng)的 webpack-obfuscator 和 javascript-obfuscator 版本過高導(dǎo)致報錯
查看 webpack 對應(yīng) webpack-obfuscator 版本可以去 git 官網(wǎng)的 tags 的 package.json 上進(jìn)行詳細(xì)查看
git 官網(wǎng): https://github.com/javascript-obfuscator/webpack-obfuscator/tags

運行npm run build 打包時出現(xiàn)錯誤 TypeError: Cannot read property ‘sourceAndMap’ of undefined

npm官網(wǎng)文檔也寫到了 Warning: right now plugin does not support sourceMap and sourceMapMode options!

解決方法:
修改 configureWebpack 配置, 將configureWebpack的對象模式改成函數(shù)形式

配置如下:
module.exports = {
configureWebpack: (config) => {
if (process.env.NODE_ENV === 'production') {
config.plugins.push(
new WebpackObfuscator({
// 壓縮代碼
compact: true,
// 是否啟用控制流扁平化(降低1.5倍的運行速度)
controlFlowFlattening: false,
// 隨機(jī)的死代碼塊(增加了混淆代碼的大小)
deadCodeInjection: false,
// 此選項幾乎不可能使用開發(fā)者工具的控制臺選項卡
debugProtection: false,
// 如果選中,則會在“控制臺”選項卡上使用間隔強(qiáng)制調(diào)試模式,從而更難使用“開發(fā)人員工具”的其他功能。
debugProtectionInterval: false,
// 通過用空函數(shù)替換它們來禁用console.log,console.info,console.error和console.warn。這使得調(diào)試器的使用更加困難。
disableConsoleOutput: true,
// 標(biāo)識符的混淆方式 hexadecimal(十六進(jìn)制) mangled(短標(biāo)識符)
identifierNamesGenerator: 'hexadecimal',
log: false,
// 是否啟用全局變量和函數(shù)名稱的混淆
renameGlobals: false,
// 通過固定和隨機(jī)(在代碼混淆時生成)的位置移動數(shù)組。這使得將刪除的字符串的順序與其原始位置相匹配變得更加困難。如果原始源代碼不小,建議使用此選項,因為輔助函數(shù)可以引起注意。
rotateStringArray: true,
// 混淆后的代碼,不能使用代碼美化,同時需要配置 cpmpat:true;
selfDefending: true,
// 刪除字符串文字并將它們放在一個特殊的數(shù)組中
stringArray: true,
rotateUnicodeArray: true,
// stringArrayEncoding: 'base64',
stringArrayEncoding: ['base64'],
stringArrayThreshold: 0.75,
// 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對小型源代碼啟用此選項。
unicodeEscapeSequence: false,
// 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對小型源代碼啟用此選項。
transformObjectKeys: true,
})
)
}
},
}總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vue自定義橫向滾動條css導(dǎo)航兩行排列布局實現(xiàn)示例
這篇文章主要為大家介紹了vue自定義橫向滾動條css導(dǎo)航兩行排列布局實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
用vue2.0實現(xiàn)點擊選中active其他選項互斥的效果
這篇文章主要介紹了用vue2.0實現(xiàn)點擊選中active其他選項互斥的效果,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04
VUE中使用TypeScript裝飾器實現(xiàn)表單驗證的全過程
這篇文章主要給大家介紹了關(guān)于如何在VUE中使用TypeScript裝飾器實現(xiàn)表單驗證的相關(guān)資料,文中通過實例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2022-03-03

