使用webpack-obfuscator進(jìn)行代碼混淆及報(bào)錯(cuò)解決過(guò)程
背景
隨著前端技術(shù)的發(fā)展,特別是單頁(yè)應(yīng)用(SPA)的普及,越來(lái)越多的應(yīng)用邏輯和業(yè)務(wù)代碼暴露在客戶(hù)端瀏覽器中運(yùn)行。
這使得應(yīng)用代碼容易被查看、復(fù)制甚至修改,從而可能引發(fā)安全問(wèn)題或商業(yè)機(jī)密泄露。
可以通過(guò)瀏覽器控制臺(tái)查看頁(yè)面源碼, 如下圖:
webpack-obfuscator 介紹
webpack-obfuscator
是一個(gè)用于混淆 Webpack
打包后的 JavaScript
代碼的插件。它通過(guò)對(duì)代碼進(jìn)行混淆處理,使原始代碼變得難以閱讀和理解,從而保護(hù)代碼的知識(shí)產(chǎn)權(quán)和業(yè)務(wù)邏輯。
這種混淆通常包括變量重命名、字符串加密、控制流扁平化等技術(shù)手段。webpack-obfuscator
可以在構(gòu)建過(guò)程中對(duì) JavaScript
代碼進(jìn)行混淆,使其在部署到生產(chǎn)環(huán)境時(shí)更加安全。
安裝
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
注意: 上面安裝的版本對(duì)應(yīng)的 webpack 4.47.0版本, 如果是 webpack 是低版本,對(duì)應(yīng)的插件版本也要降低
參數(shù)解析
混淆選項(xiàng) (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)識(shí)符名稱(chēng)的方式,默認(rèn)為'mangled'
。log (boolean)
: 是否記錄混淆過(guò)程,默認(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)
: 是否簡(jiǎn)化輸出代碼,默認(rèn)為true
。sourceMap (boolean | string)
: 是否生成源映射,默認(rèn)為false
。sourceMapMode (string)
: 源映射模式,默認(rèn)為'separate'
。splitStrings (boolean)
: 是否將字符串分割成多個(gè)較小的字符串,默認(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ù)組包裝器的類(lèi)型,默認(rèn)為 ‘variable’。stringArrayWrappersVarNames (Array<string>)
: 字符串?dāng)?shù)組包裝器變量名稱(chēng),默認(rèn)為空數(shù)組。stringArrayIndexShift (boolean)
: 是否對(duì)字符串?dāng)?shù)組索引進(jìn)行偏移,默認(rèn)為false
。shuffleStringArray (boolean)
: 是否打亂字符串?dāng)?shù)組,默認(rèn)為false
。transformObjectKeys (boolean)
: 是否轉(zhuǎn)換對(duì)象鍵,默認(rèn)為false
。transformObjectKeysBlackList (Array<string>)
: 不轉(zhuǎn)換的對(duì)象鍵黑名單,默認(rèn)為空數(shù)組。transformObjectKeysRecursive (boolean)
: 是否遞歸轉(zhuǎn)換對(duì)象鍵,默認(rèn)為false
。transformObjectKeysWhitelist (Array<string>)
: 轉(zhuǎn)換的對(duì)象鍵白名單,默認(rèn)為空數(shù)組。unicodeEscapeSequence (boolean)
: 是否使用 Unicode 逃逸序列,默認(rèn)為false
。useStrictSemicolons (boolean)
: 是否使用嚴(yán)格的分號(hào),默認(rèn)為false
。wrapCode (boolean)
: 是否包裹代碼,默認(rèn)為false
。wrapComments (boolean)
: 是否包裹注釋?zhuān)J(rèn)為false
。
排除選項(xiàng) (exclude)
exclude (Array<string> | RegExp)
: 排除不需要混淆的模塊或文件。
請(qǐng)注意,上述配置示例包含了所有可用的參數(shù),但在實(shí)際項(xiàng)目中,你可能只需要設(shè)置其中的一部分。
強(qiáng)烈建議根據(jù)項(xiàng)目需求調(diào)整這些選項(xiàng),以達(dá)到最佳的混淆效果并保持代碼的可維護(hù)性和性能。
配置示例
接下來(lái),在你的 webpack.config.js 文件中配置 webpack-obfuscator 插件。
以下是一個(gè)簡(jiǎn)單的示例配置:
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倍的運(yùn)行速度) controlFlowFlattening: false, // 隨機(jī)的死代碼塊(增加了混淆代碼的大小) deadCodeInjection: false, // 此選項(xiàng)幾乎不可能使用開(kāi)發(fā)者工具的控制臺(tái)選項(xiàng)卡 debugProtection: false, // 如果選中,則會(huì)在“控制臺(tái)”選項(xiàng)卡上使用間隔強(qiáng)制調(diào)試模式,從而更難使用“開(kāi)發(fā)人員工具”的其他功能。 debugProtectionInterval: false, // 通過(guò)用空函數(shù)替換它們來(lái)禁用console.log,console.info,console.error和console.warn。這使得調(diào)試器的使用更加困難。 disableConsoleOutput: true, // 標(biāo)識(shí)符的混淆方式 hexadecimal(十六進(jìn)制) mangled(短標(biāo)識(shí)符) identifierNamesGenerator: 'hexadecimal', log: false, // 是否啟用全局變量和函數(shù)名稱(chēng)的混淆 renameGlobals: false, // 通過(guò)固定和隨機(jī)(在代碼混淆時(shí)生成)的位置移動(dòng)數(shù)組。這使得將刪除的字符串的順序與其原始位置相匹配變得更加困難。如果原始源代碼不小,建議使用此選項(xiàng),因?yàn)檩o助函數(shù)可以引起注意。 rotateStringArray: true, // 混淆后的代碼,不能使用代碼美化,同時(shí)需要配置 cpmpat:true; selfDefending: true, // 刪除字符串文字并將它們放在一個(gè)特殊的數(shù)組中 stringArray: true, rotateUnicodeArray: true, // stringArrayEncoding: 'base64', stringArrayEncoding: ['base64'], stringArrayThreshold: 0.75, // 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對(duì)小型源代碼啟用此選項(xiàng)。 unicodeEscapeSequence: false, // 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對(duì)小型源代碼啟用此選項(xiàng)。 transformObjectKeys: true, // 排除選項(xiàng) exclude: [/node_modules/, /\.min\.js$/] }) ) } }, }
代碼混淆后
運(yùn)行 npm run dev 報(bào)錯(cuò) Error: The number of constructor arguments in the derived class t must be >= than the number of constructor arguments of its base class.
上述報(bào)錯(cuò)說(shuō)明項(xiàng)目的 webpack
版本對(duì)應(yīng)的 webpack-obfuscator
和 javascript-obfuscator
版本過(guò)低導(dǎo)致報(bào)錯(cuò)
運(yùn)行 npm run dev 報(bào)錯(cuò) TypeError: Cannot read property ‘tap’ of undefined
上述報(bào)錯(cuò)說(shuō)明項(xiàng)目的 webpack
版本對(duì)應(yīng)的 webpack-obfuscator
和 javascript-obfuscator
版本過(guò)高導(dǎo)致報(bào)錯(cuò)
查看 webpack
對(duì)應(yīng) webpack-obfuscator
版本可以去 git 官網(wǎng)的 tags
的 package.json
上進(jìn)行詳細(xì)查看
git 官網(wǎng): https://github.com/javascript-obfuscator/webpack-obfuscator/tags
運(yùn)行npm run build 打包時(shí)出現(xiàn)錯(cuò)誤 TypeError: Cannot read property ‘sourceAndMap’ of undefined
npm官網(wǎng)文檔也寫(xiě)到了 Warning: right now plugin does not support sourceMap and sourceMapMode options!
解決方法:
修改 configureWebpack 配置, 將configureWebpack
的對(duì)象模式改成函數(shù)形式
配置如下:
module.exports = { configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { config.plugins.push( new WebpackObfuscator({ // 壓縮代碼 compact: true, // 是否啟用控制流扁平化(降低1.5倍的運(yùn)行速度) controlFlowFlattening: false, // 隨機(jī)的死代碼塊(增加了混淆代碼的大小) deadCodeInjection: false, // 此選項(xiàng)幾乎不可能使用開(kāi)發(fā)者工具的控制臺(tái)選項(xiàng)卡 debugProtection: false, // 如果選中,則會(huì)在“控制臺(tái)”選項(xiàng)卡上使用間隔強(qiáng)制調(diào)試模式,從而更難使用“開(kāi)發(fā)人員工具”的其他功能。 debugProtectionInterval: false, // 通過(guò)用空函數(shù)替換它們來(lái)禁用console.log,console.info,console.error和console.warn。這使得調(diào)試器的使用更加困難。 disableConsoleOutput: true, // 標(biāo)識(shí)符的混淆方式 hexadecimal(十六進(jìn)制) mangled(短標(biāo)識(shí)符) identifierNamesGenerator: 'hexadecimal', log: false, // 是否啟用全局變量和函數(shù)名稱(chēng)的混淆 renameGlobals: false, // 通過(guò)固定和隨機(jī)(在代碼混淆時(shí)生成)的位置移動(dòng)數(shù)組。這使得將刪除的字符串的順序與其原始位置相匹配變得更加困難。如果原始源代碼不小,建議使用此選項(xiàng),因?yàn)檩o助函數(shù)可以引起注意。 rotateStringArray: true, // 混淆后的代碼,不能使用代碼美化,同時(shí)需要配置 cpmpat:true; selfDefending: true, // 刪除字符串文字并將它們放在一個(gè)特殊的數(shù)組中 stringArray: true, rotateUnicodeArray: true, // stringArrayEncoding: 'base64', stringArrayEncoding: ['base64'], stringArrayThreshold: 0.75, // 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對(duì)小型源代碼啟用此選項(xiàng)。 unicodeEscapeSequence: false, // 允許啟用/禁用字符串轉(zhuǎn)換為unicode轉(zhuǎn)義序列。Unicode轉(zhuǎn)義序列大大增加了代碼大小,并且可以輕松地將字符串恢復(fù)為原始視圖。建議僅對(duì)小型源代碼啟用此選項(xiàng)。 transformObjectKeys: true, }) ) } }, }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
element-plus dialog v-loading不生效問(wèn)題及解決
這篇文章主要介紹了element-plus dialog v-loading不生效問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03Vue實(shí)現(xiàn)拖拽穿梭框功能四種方式實(shí)例詳解
這篇文章主要介紹了Vue實(shí)現(xiàn)拖拽穿梭框功能四種方式,使用原生js實(shí)現(xiàn)拖拽,VUe使用js實(shí)現(xiàn)拖拽穿梭框,結(jié)合實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-09-09vue項(xiàng)目中Toast字體過(guò)小,沒(méi)有邊距的解決方案
這篇文章主要介紹了vue項(xiàng)目中Toast字體過(guò)小,沒(méi)有邊距的解決方案。具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04Vuejs對(duì)象常用操作之取對(duì)應(yīng)的值、取key和value值、轉(zhuǎn)數(shù)組及合并等
最近在學(xué)Vue和javascript感覺(jué)js的好多方法都不太清楚,這里徹底總結(jié)下,這篇文章主要給大家介紹了關(guān)于Vuejs對(duì)象常用操作之取對(duì)應(yīng)的值、取key和value值、轉(zhuǎn)數(shù)組及合并等的相關(guān)資料,需要的朋友可以參考下2024-01-01vue框架編輯接口頁(yè)面下拉級(jí)聯(lián)選擇并綁定接口所屬模塊
這篇文章主要為大家介紹了vue框架編輯接口頁(yè)面實(shí)現(xiàn)下拉級(jí)聯(lián)選擇以及綁定接口所屬模塊,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05vue中keep-alive,include的緩存問(wèn)題
這篇文章主要介紹了vue中keep-alive,include的緩存問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11