最近在玩台灣運彩,有時候會到官方網站查比賽賠率,看著看著就會想打開開發者工具看一下有沒有什麼有趣的地方
於是案F12想打開開發者工具,但按了之後卻發現網站居然可以偵測到當前使用者有沒有打開開發者工具,並且提示要關掉之後才能繼續瀏覽。

原本認為作法可能就是偵測鍵盤keydown事件來判斷,但後來想想可以開啟devTool的方式也不只有鍵盤,於是用右鍵打開menu並且案檢視之後發現居然這樣也可以偵測到,這就讓我很感興趣,接著就研究了一下是怎麼實作的,紀錄了兩個實作的方式,也列出方法的優缺點,跟大家分享。
(先附上 Github Demo 網址連結)
方法1
禁用可以打開開發者工具的快捷鍵

但是只有禁用快捷鍵的話,右鍵點擊檢查一樣可以打開
所以加上一段code,把右鍵menu的事件也禁用掉

完成了,快捷鍵打不開,按滑鼠右鍵,也已經沒有任何反應了,這樣沒問題了吧?
這樣確實是無法打開,但是還有以下兩個情境
1.右鍵整個被禁用,但是我按右鍵只是想複製某段文字,現在要怎麼複製?
2.在這個網站鎖掉打開開發者工具的快捷鍵,那如果我一開始先打開才導到這個網站不就沒用了?
所以這個方法顯然不太合適,接著看Demo網站使用的方法2
方法2
透過debugger會讓thread阻塞的特性,偵測是否開啟DevTool
講這個方法前必須先說到一些前置知識
1.Debugger
Debugger是一個偵錯用的工具,以常用的偵錯方式主要都是console.log,Debugger有自己的特性以及優點,這邊就不展開講,主要先簡單介紹。以MDN的範例來看,我們主要要了解 debugger 會在宣告處將程式暫停執行,就是程式碼的斷點。

2.Web Worker
大家都熟知JavaScript是單執行緒,而Web Worker提供在主執行緒外的額外執行緒,這樣藉由分派任務給Web Worker來降低主執行緒的阻塞情況,提升執行效率。
不過與主執行緒的溝通方式就需要我們自己實作,範例如下(MDN)

接著回到主題"偵測是否開起開發者工具",用剛剛了解知識的來實作功能
實作邏輯
1.建立一個 Web worker 與主線程定時進行溝通(以polling方式確認)
2.初始時Web worker啟用debugger(當devtool被開啟時,Web worker會被阻塞)
3.主線程啟用定時器來決定Web worker預期關閉的時間(假設約定時間為5秒,則5秒後會判斷Web worker是否關閉)
4.主線程於約定時間檢查 Web worker當前狀態 (若發現未關閉,此時主線程則判定使用者開啟devtool,觸發devtoolOpen)
5.當devtool被關閉時,Web worker可以繼續往下執行原先未執行完畢的程式(執行postMessage : false,令主線程能得知devtool已關閉)
6.主線程得知devtool關閉後,則將Web worker狀態重置,等待下次開啟,重複循環。

補充說明
當接收到devToolOpen事件時,你是選擇提示User,例如彈出對話框”不可開啟開發者人員工具”
在這種情況下,如果對方知道怎麼關閉debugger就能輕鬆繞過
Step1 . Ctrl + F8 (關閉斷點)
Step2 . F8 (暫停腳本執行)
如果想避開User關閉debugger,另一種做法是接收到devToolOpen事件時直接將網頁關閉。

總結
這種作法其實大概知道就好,最根本還是必須要確保網頁的安全,例如伺服器會對每個請求做驗證,而不是禁用使用者打開開發者工具。換句話說,即便使用者打開開發者工具,也要確保網頁不會因為任何操作間接或直接影響到安全性。
如果你的網頁在用戶可以訪問開發人員工具的情況下不安全,那麼它就是不安全的。