如何防止他人惡意調(diào)試你的web程序
大廠技術(shù) 高級(jí)前端 Node進(jìn)階
點(diǎn)擊上方 程序員成長(zhǎng)指北,關(guān)注公眾號(hào)
回復(fù)1,加入高級(jí)Node交流群

1前言
看到社區(qū)很多都在討論如何調(diào)試,如何高級(jí)的調(diào)試,以及一些調(diào)試的奇技淫巧,今天我想和大家聊聊,怎么禁止調(diào)試,禁止他人調(diào)試我們的程序
為什么會(huì)有這篇文章呢,源自一次我尋找盜版電影的遭遇,一次好奇心的驅(qū)使下,由于很多這種平臺(tái)都是只做搬運(yùn),不做存儲(chǔ),因?yàn)榇鎯?chǔ)盜版電影向他人提供是違法的,特別是那種剛出的新電影! 當(dāng)時(shí)好奇想通過看某站的控制臺(tái),想了解一下他們是怎么是通過啥接口,怎么請(qǐng)求,請(qǐng)求來(lái)的格式啥樣的,抱著這樣的好奇心,開始了我的奇妙之旅...
看完本篇文章你將學(xué)會(huì)
我無(wú)法斷定你能學(xué)到什么,但是以下是我希望你能從本篇文章中學(xué)到的:
-
如何簡(jiǎn)單的防止你的程序被他人惡意調(diào)試 -
逆向思維學(xué)會(huì)如何更好的調(diào)試
2具體實(shí)現(xiàn)
防止調(diào)試的方法,這里我們主要是通過不斷debugger的方法來(lái)瘋狂輸出斷點(diǎn),讓控制臺(tái)打開后程序就無(wú)法正常執(zhí)行
我們都知道debugger只有在控制臺(tái)被打開的時(shí)候才會(huì)執(zhí)行,所以后面的所有方法都是圍繞著這一特性來(lái)進(jìn)行,廢話不多說(shuō),我將通過以下幾個(gè)案例向你們展示道高一尺魔高一丈的道理,先上代碼:
方法一:
(() => {
function block() {
setInterval(() => {
debugger;
}, 50);
}
try {
block();
} catch (err) {}
})();
通過上方的代碼我們可以看到,在頁(yè)面中打開控制臺(tái)后,會(huì)有以下結(jié)果:
需要在這里說(shuō)明以下幾點(diǎn):
-
程序被 debugger阻泄了,我們無(wú)法像以往一樣在 Source Tab 中的對(duì)應(yīng) js 代碼處添加斷點(diǎn)調(diào)試,無(wú)法調(diào)試程序的執(zhí)行邏輯.在程序異常復(fù)雜且被混淆后的代碼是異常難讀的!通常我們會(huì)在 source 的左邊加上breakpoint來(lái)讓程序每次走到加點(diǎn)的地方停下來(lái),以便讓我們查看一些變量的值或是步驟的流程邏輯(如下圖所示)
-
我們都知道,第一次打開控制臺(tái)是看不到 network tab 中的任何請(qǐng)求的,所以我們想通過 network tab 來(lái)查看網(wǎng)頁(yè)都做了哪些請(qǐng)求,也是看不到的,當(dāng)我們打開控制臺(tái)就會(huì)出 debugger阻擋我們,我們可以通過下面的解決方法來(lái)處理,或者是用抓包工具來(lái)查看具體的請(qǐng)求
大家可以先不看解決方法,想想如果是你,這個(gè)時(shí)候怎么突破這個(gè)屏障呢? 第一次遇到這種情況我也是很懵,不知道咋處理,后面發(fā)現(xiàn)問題簡(jiǎn)直不要太簡(jiǎn)單,我們可以帶著疑問來(lái)看:
對(duì)于第一個(gè)示例,我們?nèi)绾谓鉀Q?(繞過它)
答案是: 禁止斷點(diǎn)
可以看到很簡(jiǎn)單,在 Chrome 控制臺(tái)的 Source Tab 頁(yè)點(diǎn)擊 Deactivate breakpoints 按鈕或者按下 Ctrl + f8(如下圖所示)。但是對(duì)于控制臺(tái)不熟悉的小伙伴,很難會(huì)想到這里去.
但是,難道這篇文章就這樣結(jié)束了?那我可頂不住小伙伴們的 "就這?" ??
其實(shí),上面的解決方法并沒有幫我們解決根本問題,我們需要做的是調(diào)試,上面雖然把debugger都去掉了,但是我們也無(wú)法在通過點(diǎn)擊每一行代碼左邊的行號(hào)添加 breakpoint 了,所以根本性的問題,并沒有解決,只是去除了那礙眼的瘋狂 debugger,我們還是得另辟蹊徑
方法二:
對(duì)對(duì)應(yīng)的代碼行,通過添加logpoint為 false,然后按回車后刷新網(wǎng)頁(yè),發(fā)現(xiàn)成功跳過無(wú)限 debugger,于是我們就可以愉快的自由調(diào)試了~
對(duì)應(yīng)的還有一種方法
即通過add script ignore list來(lái)添加需要忽略執(zhí)行代碼行或文件

可以看到,我們也可以通過刪除 script ignore list 里已添加的忽略代碼,恢復(fù)初始狀態(tài)
但是,你這么聰明,那人家不得想想對(duì)策?
對(duì)于上面的第一個(gè)方法 ??
將setInterval(() => {debugger;}, 50);寫在一行中,你即使通過添加logpoint為 false,也沒用,仍然是瘋狂 debugger,即使你可能想到,通過左下角的代碼格式化,來(lái)格式一下setInterval(() => {debugger;}, 50);將它變成多行的,也是沒用的,仍然會(huì)在刷新后重新彈 debugger
(() => {
function block() {
setInterval(() => {debugger;}, 50);
}
try {
block();
} catch (err) {}
})();
對(duì)于第二個(gè)方法,我們對(duì)代碼進(jìn)行如下改造??
(() => {
function block() {
setInterval(() => {
Function("debugger")();
}, 50);
}
try {
block();
} catch (err) {}
})();
我們可以通過將debugger改寫成Function("debugger")();的形式,來(lái)應(yīng)對(duì);Function 構(gòu)造器生成的 debugger 會(huì)在每一次執(zhí)行時(shí)開啟一個(gè)臨時(shí) js 文件,哈哈~對(duì)方表示好無(wú)奈 ??
于是會(huì)有以下結(jié)果
這無(wú)限套娃,真夠狠的,我們要堅(jiān)信正義最后總會(huì)勝利,不能給想非法調(diào)試我們程序的人機(jī)會(huì),所以我們要把各種情況都考慮周全,可以說(shuō)這種方法是最恨的,但是這還不算完~ (好家伙~ ?? 想非法調(diào)試我程序,那你就得戰(zhàn)勝我)
強(qiáng)化以上方法
上面的代碼由于沒有加密混淆,多少可能還是會(huì)被別人讀一些,那么我們加密混淆看看是啥樣的
好家伙,你這咋讀?
eval(function(c,g,a,b,d,e){d=String;if(!"".replace(/^/,String)){for(;a--;)e[a]=b[a]||a;b=[function(f){return e[f]}];d=function(){return"\\w+"};a=1}for(;a--;)b[a]&&(c=c.replace(new RegExp("\\b"+d(a)+"\\b","g"),b[a]));return c}('(()=>{1 0(){2(()=>{3("4")()},5)}6{0()}7(8){}})();',9,9,"block function setInterval Function debugger 50 try catch err".split(" "),0,{}));
格式化后的樣子
我們繼續(xù)對(duì)代碼進(jìn)行改造,讓對(duì)方盡量的難以識(shí)別我們的代碼
將Function("debugger").call()改成(function(){return false;})["constructor"]("debugger")["call"]();并且,添加條件,當(dāng)窗口外部寬高,和內(nèi)部寬高的差值大于一定的值,我把 body 里的內(nèi)容全部清空掉,看你還能不能操作我的按鈕啊啥的~哈哈哈 ??
需要特別說(shuō)明的是: 像 toG 的項(xiàng)目或者是一些為了保護(hù)自己的版權(quán)又或者是一些比較敏感的項(xiàng)目,出于安全的考慮在部署到生產(chǎn)環(huán)境后最好是不讓別人調(diào)試的,當(dāng)然,前端所做的也就那么一些,需要前后端一起配合,便可以很好的對(duì)項(xiàng)目或者數(shù)據(jù)進(jìn)行私密的保護(hù) ??
最后: 附上這份未混淆的來(lái)之不易的的代碼(記得混淆后使用哦~) ?? 一定要記得點(diǎn)贊加關(guān)注~原創(chuàng)太不容易了.
你可以把它當(dāng)作你的工具函數(shù),在需要不讓別人輕易調(diào)試的項(xiàng)目中引用
(() => {
function block() {
if (
window.outerHeight - window.innerHeight > 200 ||
window.outerWidth - window.innerWidth > 200
) {
document.body.innerHTML =
"檢測(cè)到非法調(diào)試,請(qǐng)關(guān)閉后刷新重試!";
}
setInterval(() => {
(function () {
return false;
}
["constructor"]("debugger")
["call"]());
}, 50);
}
try {
block();
} catch (err) {}
})();
3推薦一個(gè)調(diào)試頁(yè)面的小技巧
說(shuō)了那么多的防止被人調(diào)試,那么最后也說(shuō)一個(gè)本人覺得眼前一亮的調(diào)試樣式的方法
通過給style標(biāo)簽添加style="display: block",contenteditable兩個(gè)屬性實(shí)現(xiàn)在頁(yè)面中便捷的調(diào)試樣式
復(fù)制下方代碼到你的 html 文件中,玩一下~
<!DOCTYPE html>
<body>
<div>來(lái)調(diào)試我吧~</div>
<style style="display: block" contenteditable>
body {
background-color: rgb(140, 209, 230);
color: white;
}
div {
background-color: green;
width: 300px;
height: 300px;
line-height: 300px;
text-align: center;
}
</style>
</body>
4最后
我所知道的禁止調(diào)試的方法就只有如上所述,但是肯定還有很多好玩的,小伙伴們可以在評(píng)論區(qū)留言,一起共同學(xué)習(xí)~
最后拋出一個(gè)問題,如何監(jiān)測(cè)控制臺(tái)是否被打開(我上面提到過),感興趣且有頭緒,或者已經(jīng)有方法的小伙伴可以小伙伴可以在評(píng)論下方說(shuō)說(shuō)自己的想法,也可以加我們交流群一起玩耍~
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對(duì)Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
“分享、點(diǎn)贊、在看” 支持一波
