JS禁止打開控制台


主要為了通過禁止打開控制台,防止別人進行代碼調試。

1、禁止右鍵查看源碼和F12

//禁止F12鍵盤事件 document.addEventListener('keydown', function(event){    return 123 != event.keyCode || (event.returnValue = false) }); //禁止右鍵、選擇、復制 document.addEventListener(‘'contextmenu'’, function(event){    return event.returnValue = false })

破解:還可以使用瀏覽器菜單中的開發者工具打開控制台

 

2、通過頁面寬度變化監測控制台

瀏覽寬高變化監測主要是監測瀏覽器可視區域的寬高:window.innerWidth / window.innerHeight(滾動條和內容區)和瀏覽器寬高:window.outerWidth / window.outerHeight(inner的基礎上加上工具條的寬高)之間的差值。

因為我們不知道瀏覽器是否開啟了工具條及工具條的寬高,所以我們設置一個閾值如200,如果outer – inner 大於200,我們就認為開啟了控制台。

function resize(){ var threshold = 200; var widthThreshold = window.outerWidth - window.innerWidth > threshold; var heightThreshold = window.outerHeight - window.innerHeight > threshold; if(widthThreshold || heightThreshold){ console.log('控制台打開了') } } window.addEventListener('resize', resize); resize()

關於檢測窗口大小,有人專門針對此寫了個庫:https://github.com/sindresorh...,感興趣的可以去看一下。

破解:監測瀏覽器寬高變化的缺點是非常明顯的,因為這種監測只能針對控制台內嵌的情形,但是很多瀏覽器都支持獨立窗口式的控制台。

 

3、利用控制台特性改寫對象toString

對於一些瀏覽器,如果控制台輸出的是對象,則保留對象的引用,每次打開控制台的時候,如果對象類型是function、date等(以前還有regexp,現在已失效),都會重新調用一下對象的toString()方法,將返回結果打印到控制台上。

經過測試:
1)、先聲明對象,再重寫toString,最后打印對象,那么toString會在開始時多運行一次,所以可以使用一個計數器來判斷哪次有效
2)、先聲明對象,再打印對象,最后重寫toString,那么如果初始化時控制台是開啟狀態,會檢測不到這一次的狀態
3)、先聲明對象,再重寫toString,最后打印對象,但是對象不作為第一個參數,此時就可以成功監測每一次控制台狀態了
4)、console.log、console.info、console.error等均有效
5)、只在chrome內核瀏覽器有效,firefox、ie失效

var devtools = new Date(); //function(){}; devtools.toString = function() { console.log('控制台打開了'); //或執行一段死循環 window.open("about:blank", "_self"); } console.log('', devtools);

破解:可通過標簽注入js代碼清空控制台(添加一個網頁標簽,標簽網址為JavaScript:console.clear();,進入網頁后,點擊該標簽頁,就會運行里面的代碼),如果是定時器執行上述代碼,還需要重寫清空

console(JavaScript:console.clear();for(var k in console){if(typeof console[k] == 'function'){console[k] = function(){}}};)。

 

4、利用控制台特性進行監聽dom屬性

大部分瀏覽器在打印dom元素的時候,如果控制台處於關閉狀態,不會獲取元素屬性,但是如果控制台處於開啟狀態,就會自動獲取dom屬性,從而觸發監聽事件

function observerConsole(){ //這里使用dom元素,在打開控制台時才會計算id var dom = document.createElement("div") Object.defineProperty(dom, "id", { get: function(){ console.log('控制台打開了') } }) //ie不支持console.table //console.info(dom); console.log(dom); }

除了使用console.log,我們還可以使用console.info,console.dir和console.error等等,需要注意的是ie不支持console.table

破解:通過標簽注入js代碼清空控制台,如果是定時器執行打印dom的操作,還需要重寫清空console。

上述方法需要注意瀏覽器對於defineProperty的支持,另外在firefox瀏覽器失效,因為firefox瀏覽器對於對象中監聽的屬性不會取值,需要手動點開才會觸發。所以對於firefox需要另辟蹊蹺才行,這里我選擇使用debugger語句來實現,debugger 語句調用任何可用的調試功能,可以阻斷代碼執行,如果沒有調試功能可用,則此語句不起作用。所以我們可以在debugger前記錄時間,如果debugger沒有觸發,運行幾條語句的時間幾乎為0,但是如果被觸發,那間隔時間就不是幾十、幾百毫秒了。

function observerConsole(){ var obj = Object.create(null), t = Date.now(); Object.defineProperty(obj, "a", { get: function() { if(Date.now() - t > 100){ console.log('控制台打開了') } } }) setInterval(function(){ t = Date.now(); (function(){})["constructor"]("debugger")();//debugger; console.log(obj.a); }, 200) }

缺點:如果瀏覽器取消了debugger調式,那么就毫無意義了。

匯總3、4,可以做如下封裝:

var observerConsole = { openCallback: function(){ console.log('控制台打開了'); try { window.open("about:blank", "_self") } catch(e) { var btn = document.createElement("button"); btn.onclick = function() { window.open("about:blank", "_self") } btn.click() } }, observer: function(){ //這里使用dom元素,在打開控制台時才會計算id var dom = document.createElement("div"), that = this; Object.defineProperty(dom, "id", { get: function(){ that.openCallback() } }) //ie不支持console.table //console.info(dom); console.log(dom); }, observerF: function(){ var obj = Object.create(null), t = Date.now(), that = this; Object.defineProperty(obj, "a", { get: function() { if(Date.now() - t > 100){ that.openCallback() } } }) setInterval(function(){ t = Date.now(); (function(){})["constructor"]("debugger")();//debugger; console.log(obj.a); }, 200) }, init: function(){ var t = window.navigator.userAgent.toLowerCase(); t.indexOf("firefox") >= 0 ? this.observerF() : this.observer(); } } ConsoleManager.init()

破解:通過標簽注入js代碼清空控制台、取消console.log等
反破解:對console.log等進行重寫再包裝,如

let _console = { log : console.log, info : console.info, warn : console.warn, error : console.error };

然后使用_console.log等替換上面的console.log。這里可以使用閉包,防止別人對_console的再重寫。

代碼測試僅測試了firefox、ie、chrome瀏覽器及部分chrome內核瀏覽器(如360、qq瀏覽器、UC瀏覽器、搜狗瀏覽器)

資源搜索網站大全 https://www.renrenfan.com.cn 廣州VI設計公司https://www.houdianzi.com

5、利用debugger的特性,無限遞歸

這個方法不能監測控制台被打開,但是能達到不讓別人瀏覽你代碼的目的。

上面也說了:debugger 語句調用任何可用的調試功能,可以阻斷代碼執行,如果沒有調試功能可用,則此語句不起作用。

另外:每個瀏覽器都有其最大調用棧,如果超出就會拋出Maximum call stack size exceeded的錯誤並終止程序。

利用上面講的特性組合成下面的代碼:

function check() { function doCheck(a) { (function() {}["constructor"]("debugger")()); //debugger doCheck(++a); } try { doCheck(0) } catch(err) { console.log(err) } };

上面代碼check運行時,如果控制台未開啟,debugger 不會起作用,但是doCheck會不斷循環,直至爆棧,拋出錯誤,中止本次check運行;如果控制台開啟,則會不斷的進行斷點調試和循環doCheck的調用,直至爆棧;如果控制台開啟,但是取消了debugger調式,雖然此時debugger 不會起作用,但遞歸是依然存在的,而且此時網頁性能與未開啟控制台相比會大幅度下降,嚴重的話,可能會卡死瀏覽器。

未開啟控制台時代碼運行時間:
Chrome:30-50ms Firefox:200-400ms Ie:10-30ms 開啟控制台但取消debugger時代碼運行時間: Chrome:1000-2000ms Firefox:頁面直接卡死

從上面的測試結果來看,我們可以設置一個間隔2000ms的定時器來不斷執行check,這樣當控制台開啟時,不論是否取消debugger調式,都會使頁面卡住。另外我們還可以對代碼進行混淆,增加閱讀困難度,我們還可以利用閉包完成上面操作,防止別人在控制台重置check:check=function(){}。

!function(){ var _0x1cbb = ["tor", "struc", "call", "ger", "con", "bug", "de", "apply"]; setInterval(check, 2e3); function check() { function doCheck(_0x1834ff) { if (('' + _0x1834ff / _0x1834ff)['length'] !== 0x1 || _0x1834ff % 0x14 === 0x0) { (function() {return !![]}[ _0x1cbb[0x4] + _0x1cbb[0x1] + _0x1cbb[0x0] ]( _0x1cbb[0x6] + _0x1cbb[0x5] + _0x1cbb[0x3] )[_0x1cbb[0x2]]()); } else { (function() {return ![]}[ _0x1cbb[0x4] + _0x1cbb[0x1] + _0x1cbb[0x0] ]( _0x1cbb[0x6] + _0x1cbb[0x5] + _0x1cbb[0x3] )[_0x1cbb[0x7]]()); } doCheck(++_0x1834ff); } try { doCheck(0) } catch(err) { } }; }();


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM