按下 F12 的那一秒,頁面就知道你在看什麼:BOSS 直聘的控制臺偵測,是一套被藏起來的介面
從 BOSS 直聘網頁端偵測開發者工具並自動刷新關閉的行為看起,觀察一個求職網站如何把反調試機制設計成一套隱形的介面。
9 月 4 日,V2EX 上出現一則貼文。一位正在找工作的使用者想在 BOSS 直聘的網頁端查自己的 token,順便跑一鍵屏蔽外包公司的腳本,於是按下了 F12,打開瀏覽器的開發者工具。幾秒之後,頁面自動關閉了。他再試,頁面反覆刷新。他在標題裡寫下這件事,語氣像是碰到了一扇會自己鎖上的門。
這則貼文四則回覆,卻在一天內累積了近千次瀏覽。因為那扇門背後的機制,比多數人以為的更精巧,也更值得從設計的角度看一遍。
一個大陣列,被拿來當計時器
回覆串裡最關鍵的一則,來自一位曾研究過這套機制的使用者。他的描述很短,但技術上的意思可以展開:當你打開開發者工具,瀏覽器會開始把 console.log 的內容序列化後顯示出來。如果程式刻意 log 一個非常大的陣列,在控制臺開啟的狀態下,這個動作會明顯比控制臺關閉時更耗時。於是頁面只要反覆測量這段輸出花了多少毫秒,就能反推出你有沒有打開控制臺。偵測成立,頁面刷新或關閉。
換句話說,這套偵測沒有呼叫任何「偵測開發者工具」的正式 API,因為瀏覽器根本沒有提供這樣的 API。它用的是瀏覽器渲染機制裡一個側面的時間差,把一個效能特徵變成了身分判斷。這是一種很典型的灰區設計:功能上有效,規範上不存在,使用者也就無從設定裡關掉它。
從產品設計的角度看,這件事有趣的地方在於它的完整度。多數網站的反調試只做一半,偵測到就跳個警告。而這裡的行為是持續的、自動的、沒有任何提示的。你打開控制臺,頁面輸出一大堆陣列,一兩秒後刷新。你不明白發生了什麼,只覺得網站壞了。錯誤感被設計成了勸退的手段。
介面消失的那一刻,才是設計最用力的地方
一套正常的介面設計,目標是讓使用者理解狀態:按鈕按下要有回饋,載入要有進度,錯誤要有訊息。這套機制剛好反過來,它刻意不給回饋。頁面刷新是使用者每天都會遇到的正常現象,把「我們偵測到你在檢查這個頁面」這件事藏進一次看似普通的刷新裡,使用者的第一反應是懷疑自己的網路,而不是意識到被攔截了。
回覆串裡另一位使用者補上了這套機制的後半段:偵測到使用外掛或腳本時,帳號或招募主體會被標記為「使用插件」,接著開始限流、漲價,而且沒有任何申訴管道可以解除。如果把這兩層加在一起看,整個系統的輪廓就清楚了:前端用時間差做隱形偵測,後端用標記做差別待遇,而貫穿兩者的是一致的沉默。沒有警告彈窗,沒有違規通知,沒有解釋。
這是一種把懲罰設計成環境的作法。使用者體驗到的不是「被處罰」,而是「這個網站變難用了」。徵才方發現曝光變少、費用變高,求職方發現腳本失效、頁面閃退,但沒有任何一個畫面告訴你原因。介面的缺席,本身就是這套系統最主要的介面。
拿它跟誰比
同一件事在別的場景裡有截然不同的處理方式。電商平臺偵測到搶票腳本,通常會跳出驗證碼,把人機判斷攤在使用者面前;遊戲反作弊系統偵測到外掛,至少會有一份封禁通知。這些設計都保留了「告知」這一環,因為告知本身就是嚇阻力的一部分。而這裡選擇了完全不告知,把成本壓到最低、把混淆做到最滿。兩相比較,差別在於品牌願意為了秩序付出多少透明度。願意講規則的平臺,規則本身會成為信任的一部分;不願意講的平臺,省下的麻煩最後由使用者自行猜測。
也要公平地說,這套機制針對的行為確實存在灰色地帶。一鍵屏蔽外包的腳本,對求職者來說是篩選工具,對平臺來說是繞過付費排序的漏洞。平臺有商業理由阻止自動化存取。問題從來不在於要不要防,而在於防的方式要不要讓人知道。用一個渲染時間差做無聲偵測,再把懲罰藏進演算法的降權裡,這條路走到底,就是一個所有規則都看不見的市場。
那位最後給出解法的使用者,建議是劫持 console 物件,讓序列化不再發生。技術上這能繞過偵測,但繞過之後是什麼?是另一場更安靜的軍備競賽:平臺換一種時間差,腳本換一種劫持。而那位原發文者真正想要的東西很樸素,找到自己的 token,屏蔽掉不想看的公司。一個求職者在求職網站上想擁有的篩選權,最後變成了與網站本身之間的攻防。
回到那個最初的畫面:按下 F12,頁面幾秒後自動關閉。它看起來像一個 bug,實際上是一份寫得相當完整的設計文件,只是這份文件從來沒有打算給使用者讀。一個介面誠實與否,往往就看它願不願意說出自己在做什麼。這個頁面的答案很清楚:它什麼都不說,然後把門關上。