蜜罐表單欄位、陷阱連結與計時檢查如何在不打擾真人的前提下抓住初階機器人:隱藏欄位如何不傷及無障礙使用者,為何自動填入是誤判頭號原因,以及被誤擋時該如何自查。
蜜罐是網站能用的成本最低的機器人偵測:在頁面裡放一個真人永遠看不到、也碰不到的東西,任何與它的互動都說明訪客是程式。它幾乎不花成本,也不給真實使用者添任何麻煩,而初階機器人只要把頁面當作原始標記而非像素來讀,就會立刻暴露。
重點摘要
- 不對稱性就是全部訣竅。 真人操作的是渲染出來的內容;簡單的機器人操作的是 DOM 裡的內容。只存在於 DOM 中的陷阱就能把兩者區分開。
- 三種常見陷阱: 必須保持為空的隱藏表單欄位、指向
robots.txt已禁止之 URL 的隱藏連結,以及對表單送出速度的計時檢查。 - 真正的工程難點是不傷及身心障礙使用者。 螢幕閱讀器走訪的是 DOM,僅用 CSS 隱藏的陷阱可能困住使用輔助技術的真人。
- 自動填入是誤判的頭號原因。 密碼管理員與瀏覽器自動填入可能填上使用者從沒看過的欄位,所以被擋下的真人通常沒有做錯什麼。
- 蜜罐是第一道過濾,不是完整防禦。 它能抓住爬蟲與表單垃圾腳本,對被自動化驅動的真實瀏覽器則毫無作用。
陷阱為什麼有效
每一種機器人偵測都在問同一個問題:這個用戶端的行為像真人嗎?多數答案需要分析,例如指紋一致性或行為評分。蜜罐把問題換成「這個用戶端有沒有碰過任何真人不可能碰到的東西?」,從而省掉了分析。
真人看到的是渲染後的頁面,而表單垃圾腳本或爬蟲通常讀的是 HTML。它會找出每個 <input>,用看似合理的資料填滿並送出。如果頁面裡有一個螢幕上看不見的輸入框,腳本照樣會填,伺服器由此就能判斷:送出者根本沒有像真人那樣「看」過這個頁面。
表單欄位蜜罐
經典陷阱是在表單裡加一個視力正常的使用者永遠看不到的額外輸入框——移出畫面、設為零尺寸或設成完全透明——但它仍留在 DOM 裡,而且關鍵在於:它仍會隨表單一起送出。(disabled 的輸入框根本不會被送出,這正是陷阱要「隱藏」而不是「停用」的原因。)伺服器端的規則很簡單:只要這個欄位帶著內容送過來,就拒絕該次送出,可以靜默拒絕,也可以回傳通用錯誤。
三個設計細節決定它是否有效:
type="hidden"是最弱的版本。 隱藏輸入本來就是用來攜帶值的,任何走訪表單的腳本都知道不去動它們,或原樣帶回。陷阱必須看起來像一個期待使用者輸入的欄位。- 名稱很重要。 叫
email2或website的欄位看起來像腳本該填的東西,也像自動填入該填的東西。使用中性、無關的名稱較不容易被意外填上。 - 判定必須放在伺服器端。 用前端 JavaScript 判定的陷阱,用戶端可以直接跳過;而蜜罐要抓的那些腳本,恰恰從來不執行頁面的 JavaScript。
無障礙限制
多數蜜罐都栽在這裡。螢幕閱讀器讀的不是像素,而是走訪 DOM。僅僅移出畫面的欄位仍然會被朗讀,仍可用 Tab 鍵聚焦,可能把鍵盤或輔助技術使用者困在一個他們無法理解的欄位裡。
並不是所有 CSS 隱藏手法都一樣,而差別恰恰就是問題所在。display: none 與 visibility: hidden 確實會把元素移出無障礙樹與 Tab 順序——但寫得稍好一點的機器人在填欄位前第一件事就是查這兩個屬性,所以實作者往往改用移出畫面、零透明度或零尺寸。這些做法既讓陷阱對腳本保持「有吸引力」,也讓它對輔助技術完全暴露。
所以隱藏必須做兩遍:一遍給眼睛,一遍給無障礙樹。
- 在外層容器上使用
inert屬性,可使整個子樹無法互動、退出 Tab 順序,並對輔助技術隱藏。 - 在不支援
inert的舊環境中,aria-hidden="true"與tabindex="-1"能涵蓋其中大部分效果:輔助技術會略過該容器,Tab 鍵也會略過該輸入框,只是腳本仍可讓它取得焦點。 autocomplete="off"請求瀏覽器不要填入該欄位。具體語意請見 MDN 的autocomplete屬性說明,並注意瀏覽器把它當作提示而非保證。
合起來大致是這個樣子:
<div inert aria-hidden="true" style="position:absolute;left:-9999px">
<label for="contact-ref">Leave this field blank</label>
<input type="text" id="contact-ref" name="contact-ref"
tabindex="-1" autocomplete="off">
</div>
那個可見的 label 不是裝飾。對於繞過了上述所有措施、仍然摸到這個欄位的人來說,它是最後一道防線——所以它應該直接告訴對方該怎麼做(「請勿填寫此欄」),而不是解釋這是個陷阱。
「在視覺上藏起來」不是檢驗標準。真正的標準是:使用鍵盤與螢幕閱讀器的人能否完成表單而完全遇不到陷阱。
經典誤判:自動填入
如果你送出一般表單後被擋下,原因很可能就在這一節。密碼管理員與瀏覽器自動填入依名稱、標籤與類型比對欄位,並不在意欄位是否可見。名為 phone 或 address2 的陷阱可能被瀏覽器在背景填上,伺服器隨即把真人的送出當成「機器人」送出。
瀏覽器擴充功能改寫或注入表單值時也會發生同樣的事。這些都不是使用者做錯了什麼。好的實作會使用無關的欄位名稱與 autocomplete="off" 來降低風險,並把被填上的陷阱只當作多個訊號之一,而不是自動封鎖。
連結與路徑陷阱
同樣的思路也適用於爬蟲。網站加入一個真人看不到的連結(常帶 rel="nofollow"),指向其 robots.txt 禁止的 URL。請求該 URL 的用戶端就證明它無視了 robots.txt。
這個設計的巧妙之處,在於它不會抓到誰。你希望被收錄的搜尋引擎,如 Googlebot 與 Bingbot,遵守 robots.txt,從不請求被禁止的路徑,所以永遠不會觸發。真正中招的,恰恰是本來就不遵守網站規則的用戶端。
不過它也不是絕對乾淨。不少無害的非搜尋引擎用戶端——站點稽核爬蟲、無障礙掃描器、安全掃描器、封存機器人——會跟進它們解析到的每一個連結,而其中並非人人都會先讀 robots.txt。觸發陷阱只能證明某個用戶端無視了規則,並不能證明它懷有惡意。這也是為什麼更穩妥的做法是對相應位址限速或標記,而不是直接封鎖。
計時陷阱
第三種變體甚至不需要隱藏元素。伺服器在渲染表單時發出一個時間戳記或簽章權杖,送出時再驗證。300 毫秒就回傳的表單,不可能是真人讀過的。但權杖必須簽章或存在伺服器端:直接塞在隱藏輸入裡的裸時間戳記,只是一個用戶端回傳前想改就改的數字。
不過固定門檻很脆弱。自動填入能瞬間完成一份正常表單,老使用者清楚該填什麼,稍有耐心的機器人也只需等一等。計時最適合作為疊加在其他訊號上的弱訊號,絕不該成為拒絕的唯一理由。
蜜罐在整套防禦中的位置
蜜罐是一道廉價的第一層過濾。它能在任何昂貴偵測執行之前,抓住造成大部分表單垃圾與初階爬取的低成本腳本。對被自動化驅動的真實瀏覽器則無能為力,因為它會像真人一樣渲染頁面,腳本也可以被要求只與可見內容互動。
所以它和整條防線並存於我們的機器人偵測技術指南中:自動化旗標、無頭瀏覽器洩漏、行為分析,以及 Cloudflare「正在檢查您的瀏覽器」頁面這類挑戰系統。每一層負責抓住下面那層更廉價的偵測漏掉的東西。
如果你被擋下了
被擋下的真人幾乎總是觸發了自動填入或某個擴充功能,而不是真正的偵測。可以在自己的瀏覽器上檢查:
- 關閉密碼管理員與自動填入後重試,手動輸入各欄位。
- 停用會注入或改寫表單值的擴充功能,在乾淨的設定檔中再試一次。
- 看看你在其他網站是否也被擋。若是,問題更可能在網路或瀏覽器設定,而不是某一張表單。
想知道你的瀏覽器向網站暴露了哪些與自動化相關的訊號,可執行我們的機器人偵測。它只讀取瀏覽器本來就會回報的內容,一切都在本機執行。
常見問題
網頁表單裡的蜜罐是什麼?
一個真人看不到也不會填寫、但仍留在頁面標記中的輸入欄位。如果它帶著值回來,說明送出者讀的是 HTML 而不是渲染後的頁面,這是自動化的有力證據。
蜜罐能擋住所有機器人嗎?
不能。它抓的是簡單腳本與爬蟲。被自動化驅動的真實瀏覽器像真人一樣渲染頁面,不會碰螢幕上看不見的陷阱,所以蜜罐只是多層防禦中的一層。
蜜罐會誤擋真人嗎?
會,主要是因為自動填入與密碼管理員會填隱藏欄位,以及做得不好的陷阱會被輔助技術觸及。謹慎的實作會使用 inert、tabindex="-1" 與 autocomplete="off",並把結果只當作一個訊號。
為什麼搜尋引擎爬蟲不會中陷阱連結?
因為它們遵守 robots.txt。陷阱連結指向被禁止的路徑,守規矩的爬蟲從不請求,只有無視規則的用戶端才會。


