首先聲明一點,前端的js想做到純粹的加密目前是不可能的,所有的加密都只能說是混淆,通過一系列的處理使得源碼無法閱讀,進(jìn)而達(dá)到加密的效果。所以在本文中如果提及了JavaScript代碼加密就指代的是混淆今艺。
因為JavaScript大都是運行在瀏覽器端,這就導(dǎo)致任何人都可以直接對網(wǎng)站的代碼進(jìn)行查看,如果代碼沒有進(jìn)行任何處理就會導(dǎo)致直接暴露源碼晓勇,他人便可輕而易舉的復(fù)制你的勞動成果,但是由于沒有純粹的加密方案,所以能做的就是讓代碼變得更加的難以閱讀,他人難以復(fù)制你的成果,實現(xiàn)“加密”的目的陶耍。 在本文中,將為你介紹一些最常見的js代碼混淆手段,希望可以幫你更好的理解什么是js代碼混淆饼齿。當(dāng)然如果你的代碼比較重要,那強烈推薦你試一試 safekodo代碼加密工具张足。
好的,正文開始~
1. 變量重命名
變量重命名是 JavaScript 代碼混淆中最簡單且最常用的方法之一触创。這種方法的基本思想是將所有可能包含敏感信息的變量重命名為無意義的字符串。例如为牍,將 username
替換為 a
哼绑,將 password
替換為 b
。將變量名替換為無意義的字符串或者短字符碉咆,使得人類閱讀難度大大增加抖韩。例如:
// 沒有代碼混淆
var username = "user123";
var password = "pass456";
function login(user, pass) {
if (user === username && pass === password) {
console.log("Login successful!");
} else {
console.log("Login failed!");
}
}
login(username, password);
// 使用變量名混淆進(jìn)行代碼混淆
var a = "user123";
var b = "pass456";
function c(d, e) {
if (d === a && e === b) {
console.log("Login successful!");
} else {
console.log("Login failed!");
}
}
c(a, b);
但這種只是相當(dāng)于簡化了可讀性,實際混淆效果很差,代碼占用倒是會變小很多。
2.函數(shù)名混淆
函數(shù)名混淆是另一種常用的 JavaScript 代碼混淆技術(shù)疫铜。它的基本思想是將所有函數(shù)名替換為隨機的茂浮、無意義的字符串,從而使代碼更難被理解和調(diào)試。
以下是一個示例:
// 沒有代碼混淆
function add(x, y) {
return x + y;
}
console.log(add(2, 3));
// 使用函數(shù)名混淆進(jìn)行代碼混淆
var a = function(b, c) {
return b + c;
}
console.log(a(2, 3));
這種本質(zhì)還是和上面介紹的變量重命名一樣席揽。
3. 壓縮代碼
壓縮是另一種常見的JavaScript代碼混淆技術(shù)顽馋。通過使用各種壓縮算法,可以將JavaScript代碼文件縮小到原始大小的一半以下幌羞。同時也使用了上面介紹的變量名或者函數(shù)名混淆(下方示例的壓縮后的代碼并未對函數(shù)名進(jìn)行壓縮)例如:
function calculateSum(num1, num2) {
var sum = num1 + num2;
return sum;
}
var result = calculateSum(3, 4);
console.log(result);
可以通過壓縮代碼將其變?yōu)橐韵滦问剑?/p>
function calculateSum(a,b){return a+b}console.log(calculateSum(3,4));
雖然這樣的代碼難以閱讀寸谜,但對于需要快速加載和運行的Web應(yīng)用程序來說非常有用。
4. 字符串編碼
//文本編碼為base64
const text = "Hello, world!";
const base64 = btoa(text);
console.log(base64); // 輸出 "SGVsbG8sIHdvcmxkIQ=="
//base64解碼為文本
const base64 = "SGVsbG8sIHdvcmxkIQ==";
const text = atob(base64);
console.log(text); // 輸出 "Hello, world!"
將字符串進(jìn)行編碼属桦,不易被人讀取熊痴。例如,將"Hello, world!"轉(zhuǎn)換為"SGVsbG8sIHdvcmxkIQ=="聂宾。解密時使用base64解碼即可果善。
除了base64還可以使用十六進(jìn)制碼的形式表示了字符串中各個字符的 ASCII 碼值
具體來說,\x 是一個轉(zhuǎn)義序列系谐,后面跟隨兩個十六進(jìn)制數(shù)字巾陕,表示一個 ASCII 碼值。因此纪他,\x48 表示的是字符 "H" 的 ASCII 碼值惜论,\x65 表示的是字符 "e" 的 ASCII 碼值,依次類推止喷。
例如:
可以將代碼
var message = "Hello World!";
alert(message);
使用十六進(jìn)制碼的形式表示了字符串中各個字符的 ASCII 碼值
var _0x3d9d=["\x48\x65\x6C\x6C\x6F\x20\x57\x6F\x72\x6C\x64\x21"];alert(_0x3d9d[0]);
將這些 ASCII 碼值拼接起來,可以得到完整的字符串 "Hello World!"混聊。
4. 代碼打亂
JS 控制流混淆是一種消除JavaScript代碼的可預(yù)測性的技術(shù)弹谁,通過使用控制流混淆算法(如JScrambler),改變程序結(jié)構(gòu)來防止代碼被輕易地理解和分析的技術(shù)句喜。簡單來說预愤,就是通過修改代碼中的控制流語句(如 if、while 等)的順序咳胃、嵌套植康、去除等方式來增加代碼的復(fù)雜性,從而使得代碼難以被反編譯展懈、破解或者逆向工程攻擊销睁。以下是一個簡短的示例:
const a = 1;
const b = 2;
let c = 0;
if (a === 1) {
if (b === 2) {
c = 3;
}
} else {
c = 4;
}
這段代碼可以通過控制流混淆的方式進(jìn)行優(yōu)化。例如存崖,可以將 if
塊內(nèi)部的語句交錯冻记、嵌套,增加運算符的數(shù)量来惧,達(dá)到混淆的效果:
const a = 1;
const b = 2;
let c = 0;
if (!(a !== 1)) {
if (!(![])) c = 3;
} else {
if (!(!{})) c = 4;
}
可以看到冗栗,經(jīng)過混淆之后的代碼,不僅代碼結(jié)構(gòu)產(chǎn)生了較大的變化,同時還加入了無用的計算和類型轉(zhuǎn)換等操作隅居,使得代碼更深奧難懂钠至。
5.方法實現(xiàn)
當(dāng)需要保護(hù)JavaScript代碼的時候,常見的方式是進(jìn)行混淆胎源。通過混淆棉钧,可以使代碼難以被閱讀和修改,從而保護(hù)代碼的安全性乒融。在本文中下半部分掰盘,我們將介紹如何使用AST語法樹來進(jìn)行JavaScript代碼混淆。
什么是AST語法樹赞季?
AST(Abstract Syntax Tree)語法樹是將代碼轉(zhuǎn)換為樹形結(jié)構(gòu)的一種方式愧捕。它能夠表示出代碼的結(jié)構(gòu)和語義,可以被用于代碼分析申钩、優(yōu)化和轉(zhuǎn)換次绘。AST語法樹通常由編譯器或解釋器生成,用于在代碼執(zhí)行之前對其進(jìn)行處理撒遣。
在JavaScript中邮偎,AST語法樹可以使用工具庫如Esprima或Babel來生成。這些庫將JavaScript代碼解析為AST語法樹义黎,并提供了簡單易用的API來讓開發(fā)者進(jìn)行代碼分析和操作禾进。
使用AST語法樹進(jìn)行JavaScript代碼混淆
AST語法樹提供了一種強大的工具來進(jìn)行JavaScript代碼混淆。通過對AST語法樹進(jìn)行操作廉涕,我們可以改變代碼的結(jié)構(gòu)和語義泻云,使其變得更加難以理解和修改。
esprima狐蜕、babel都可以實現(xiàn)
下面是一些常見的AST語法樹操作:
// 變量重命名示例
const esprima = require('esprima');
const estraverse = require('estraverse');
const code = `
function add(a, b) {
let c = a + b;
return c;
}
`;
const ast = esprima.parseScript(code);
const varMap = {
'a': 'x',
'b': 'y',
'c': 'z'
};
estraverse.replace(ast, {
enter(node) {
if (node.type === 'Identifier' && varMap[node.name]) {
node.name = varMap[node.name];
}
}
});
const newCode = escodegen.generate(ast);
console.log(newCode);
// 將加號替換成減號
const code = `
const sum = (a, b) => a + b;
const result = sum(1, 2);
`;
const ast = esprima.parseScript(code);
const newAst = replaceCode(ast, "+", "-");
console.log(generate(newAst));
//babel實現(xiàn)將代碼中的所有值為false的節(jié)點并替換為![]
const parser = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
// 原始代碼
const code = `let flag = false;
if (flag) {
console.log("Flag is true");
} else {
console.log("Flag is false");
}`;
const ast = parser.parse(code);
traverse(ast, {
enter(path) {
if (path.isBooleanLiteral({ value: false })) {
path.replaceWith(parser.parse("![]").program.body[0].expression);
}
}
});
// 將AST語法樹重新生成為代碼字符串
const newCode = generator(ast).code;
// 輸出新代碼
console.log(newCode);
// 新代碼為:
// let flag = ![];
// if (flag) {
// console.log("Flag is true");
// } else {
// console.log("Flag is ![]");
// }
篇幅有限,對于babel將js代碼解析為ast語法樹這一部分后續(xù)在進(jìn)行著重介紹宠纯。
溫馨提示
如果您對AST語法樹的結(jié)構(gòu)不是很了解的話,推薦您前往safekodo官網(wǎng)使用在線的js=>ast語法樹工具,在網(wǎng)站中的編輯器輸入JavaScript代碼即可在右側(cè)看到響應(yīng)的AST語法樹結(jié)構(gòu),當(dāng)然相應(yīng)的還有ast=>js工具,非常的直觀
需要注意的是,JavaScript 代碼混淆并不能完全保證代碼的安全性层释,因為熟練的開發(fā)人員仍然可以通過不同的手段逆向工程出原始代碼婆瓜。因此,除了代碼混淆之外贡羔,我們還應(yīng)該采取其他措施來保護(hù)我們的 JavaScript 代碼廉白,例如加密算法和訪問控制等。
以上介紹的都是一些常用的簡單的JavaScript代碼混淆原理,如果你想更加簡單粗暴的保護(hù)你的源代碼,可以使用safekodo代碼加密工具進(jìn)行一步到位的代碼保護(hù)治力。safekodo支持多平臺的js代碼保護(hù)(web端蒙秒、nodejs、electron宵统、小程序晕讲、APP等 ),同時還支持眾多配置(代碼高度混淆覆获、數(shù)據(jù)多重加密、控制流扁平化處理瓢省、死代碼塊注入弄息、運行環(huán)境及時間可鎖定等等功能及方案 )
5. 總結(jié)
在本文中我們了解了什么是JavaScript代碼混淆加密,以及通過一些代碼示例明白其原理,在后面的文章中還會介紹在node/electron中使用bytenode將JavaScript代碼編譯為jsc字節(jié)碼實現(xiàn)代碼加密的效果以及一些注意事項。喜歡的話就點個關(guān)注吧??