官網表單垃圾訊息,先不要急著加驗證碼。依序做好四道真人看不見的防線就能擋下大部分:蜜罐欄位、停留時間檢查、CSRF token、同一來源的頻率限制。這四道都在伺服器端判斷,不需要外部服務、不增加客人的填寫步驟;四道都做了垃圾訊息還是持續進來,才把驗證碼加在最後一關。順序也有講究:先擋「幾乎可以確定是程式」的,再擋「有可能誤傷真人」的。
這篇以本站自己在用的表單防護元件為例。本站的線上諮詢、網址與主機訂購、合作夥伴招募三張表單,都共用同一支防護程式。文中會說明每一道在擋什麼、擋不了什麼、會不會誤傷真人,以及 2026 年 8 月 28 日到 10 月 28 日這兩個月的擋下紀錄。基於安全考量,文中不寫任何門檻數值,也不討論繞過方法。
表單垃圾訊息從哪裡來?先分清楚三種來源
「表單一直收到垃圾訊息」其實是三種不同的問題,擋法也不一樣。先看收件匣裡的垃圾訊息比較像哪一種:
| 來源 | 常見樣子 | 擋得住的機制 |
|---|---|---|
| 自動填表程式 | 每個欄位都填滿,內容是廣告連結或亂碼,常在半夜一口氣進來好幾封 | 蜜罐欄位、停留時間檢查、頻率限制 |
| 直接呼叫處理程式 | 沒有經過表單頁,直接把資料丟給處理表單的那支程式;收件匣常出現欄位是空的或格式奇怪的信 | 只收 POST、CSRF token |
| 真人手動發送 | 有人用你的表單推銷 SEO、貸款、網站改版,內容通順、欄位填得很完整 | 技術上幾乎擋不掉,只能靠內容規則或人工判斷 |
第三種要先講清楚:真人手動貼的推銷訊息,任何驗證碼都擋不住,因為發送的就是真人。所以「裝了防護還是收到推銷信」不一定代表防護沒用,要看進來的是哪一種。下面四道防線處理的是前兩種,也就是量最大、最擾人的部分。
表單垃圾訊息的 4 道防線:照誤擋機率由低到高排
本站的防護程式在處理表單之前先做一個入口檢查:只接受 POST,從網址直接打開處理程式的請求一律退回。接著依序跑四道檢查,任何一道不通過就停下來,不寄信、不寫入:
| 順序 | 機制 | 怎麼判斷 | 擋什麼 | 擋不了什麼 | 誤傷真人的機率 |
|---|---|---|---|---|---|
| 1 | 蜜罐欄位 | 表單裡藏一個人看不到的文字欄位,有值就判定為程式 | 會把所有欄位都填滿的自動填表程式 | 針對單一網站寫的程式、真人 | 極低 |
| 2 | CSRF token | 表單頁產生一組隨機值存在伺服器端,送出時比對是否一致 | 沒有先開表單頁、直接把資料丟給處理程式的請求;從別的網站偷偷代送的請求 | 會先載入表單頁再送出的程式 | 低(頁面停太久會逾時) |
| 3 | 停留時間 | 記下表單載入的時間,送出時檢查間隔:太短不像人填的,太長視為過期 | 載入後立刻送出的程式;重複使用舊表單的請求 | 刻意等待再送出的程式 | 低到中(瀏覽器自動填入很快的人) |
| 4 | 頻率限制 | 同一個來源位址在一段時間內只能送出固定次數 | 同一台機器大量灌單 | 分散在大量位址的攻擊 | 中(同一辦公室共用對外位址、客人自己重複送出) |
把誤擋機率最低的放前面,有兩個好處:確定是程式的請求在第一關就被擋下,不必消耗後面的檢查;真人就算碰到比較嚴格的檢查,也一定是已經通過前面幾關、比較可能是真客戶的人,這時擋下的訊息就要特別講究(第四節會談)。
蜜罐欄位:藏起來的方式決定會不會誤傷
蜜罐的原理很簡單,難的是「藏」。本站的做法是用 CSS 把整個欄位移到畫面外,而不是用 type="hidden",因為很多程式會跳過隱藏欄位,卻會填看起來正常的文字欄位。藏起來之後還要處理三種真人可能誤填的情況:
- 螢幕報讀軟體:加上
aria-hidden,讓視障使用者的報讀軟體略過這個欄位;欄位標籤也直接寫「看得到這個欄位請不要填寫」,萬一被讀到也不會誤填。 - Tab 鍵:設定
tabindex="-1",用鍵盤逐欄填寫的人不會跳進去。 - 瀏覽器自動填入:設定
autocomplete="off",並避免把欄位取名成姓名、電話、Email 這類瀏覽器會主動填值的名稱。
CSRF token:不只擋垃圾訊息,也擋「被別人代送」
CSRF(跨站請求偽造)指的是別的網站在訪客不知情的情況下,借訪客的瀏覽器向你的網站送出表單。token 的做法是:表單頁產生一組足夠長的隨機值,一份放在伺服器端的工作階段(session),一份放在表單的隱藏欄位,送出時兩邊比對,不一致就退回。比對時要用固定時間的比較函式(PHP 是 hash_equals()),不要用一般的字串相等。
工作階段的 cookie 也要一起設好:HttpOnly(網頁上的 JavaScript 讀不到)、Secure(只在 HTTPS 傳送)、SameSite=Lax(從別的網站送來的 POST 不帶這個 cookie)。用 Lax 而不用 Strict,是因為站內表單都是同站送出,Lax 不影響正常使用。
頻率限制:來源位址要取對
頻率限制最常見的錯誤,是把用戶端自己可以填寫的標頭(例如 X-Forwarded-For)當成訪客位址。這種標頭由送出請求的一方決定,拿它來計次,限制就形同虛設。本站主機前面沒有反向代理或 CDN,所以直接用連線本身的來源位址;日後若加了 CDN,也要先確認請求來自已知的代理,才採信它轉送的位址。
計次紀錄放在網站目錄之外,外面打不開;檔名用位址的雜湊值,不把訪客位址直接寫進檔名。舊紀錄定期清掉,避免目錄一直長大。
本站兩個月的表單擋下紀錄:多數根本沒經過表單
防護程式每擋下一次,就在主機的錯誤紀錄寫一行,記下原因、來源位址與瀏覽器識別字串。下表是 2026 年 8 月 28 日到 10 月 28 日的統計:
| 擋下原因 | 筆數 | 代表什麼 |
|---|---|---|
| 非 POST(直接開啟處理程式) | 221 | 有程式沒經過表單、直接拜訪處理程式的網址 |
| CSRF token 不符 | 1 | 送出的請求沒有對應的工作階段,可能是逾時或直接代送 |
| 超過頻率限制 | 1 | 同一來源短時間內送出太多次 |
| 蜜罐被填寫 | 0 | — |
| 填寫過快 | 0 | — |
| 合計 | 223 | 約 62 天,平均每天 3~4 筆 |
本站主機錯誤紀錄中,表單防護程式的擋下紀錄,2026-08-28~2026-10-28。非 POST 的紀錄包含搜尋引擎爬蟲、SEO 分析工具、掃描程式,也包含我們自己的檢測。
這張表可以讀出三件事:
- 大部分「打表單」的流量根本不是在填表單。223 筆裡 221 筆是直接開啟處理程式。爬蟲順著網址抓、掃描程式逐一試探常見檔名,都會落在這裡。這類請求如果沒有入口檢查,處理程式就會用一堆空值去跑寄信流程,收件匣出現的就是「欄位全空的怪信」。
- 不是每個網站都需要一開始就上驗證碼。這段期間蜜罐與填寫過快都是 0,代表打到本站的自動化流量,多半不會真的去填表單。一個中小企業的 B2B 官網,先把入口檢查與 token 做對,通常就解決了大半問題。
- 紀錄只記得被擋下的。這張表沒辦法告訴你有沒有漏網之魚,所以要和收件匣對照:垃圾訊息還是很多,就看進來的是哪一種(回到第一節的表),再決定補哪一道。
垃圾訊息除了吵,還會污染數據。如果表單送出有設成 GA4 的詢價事件,機器人送一次就算一次轉換,月報上的詢價數會比實際多;送出事件的設定方式與對帳方法見企業官網 GA4 看哪些數字。
驗證碼、內容過濾要不要加?三種補強的取捨
四道防線都做了還是擋不住,才進到這一層。每一種補強都有代價,代價都落在真客戶身上:
| 補強方式 | 擋什麼 | 代價 | 適合什麼情況 |
|---|---|---|---|
| 驗證碼(圖形、勾選或背景評分式) | 大部分自動化程式 | 多一個步驟;要載入第三方服務,牽涉隱私說明與資料傳輸;圖形驗證碼對視障與年長使用者不友善 | 四道都做了、自動化垃圾訊息仍持續進來 |
| 內容規則(連結數、關鍵字、語言) | 內容有固定特徵的推銷與廣告 | 會誤擋;客人在詢價內容貼一個網址也可能被擋 | 垃圾訊息內容高度重複時;建議標記待審而不是直接丟掉 |
| Email 驗證或回撥確認 | 假身分的詢價 | 流程變長,等不及的客人會直接去找別家 | 會員註冊、試用申請這類有後續權限的表單,不適合一般詢價 |
公部門或照顧長者族群的網站要特別注意驗證碼的無障礙問題:只有圖形、沒有替代方式的驗證碼,會讓一部分使用者完全送不出表單。表單標籤與錯誤訊息本來就是無障礙檢測的重點項目,檢測怎麼做見政府網站無障礙規範那篇。
另外,表單防護只管「誰能送進來」。送進來之後,通知信能不能寄到、會不會被當成垃圾郵件,是另一件事:通知信要從自己網域的信箱寄出,網域的 SPF、DKIM、DMARC 要設好,做法見公司寄的信一直進垃圾郵件;收件信箱建議用職務信箱,不要綁在個人帳號上,理由見公司信箱該用免費信箱還是自有網域。
擋下之後:別讓真客戶的詢價消失
表單防護最貴的失誤不是漏掉一封垃圾訊息,而是擋下一位真客戶、而且對方不知道自己被擋了。本站 2026 年 8 月實測訂購流程時,就碰過「某個分支出錯,客戶只看到一片空白頁,信一封都沒寄出」的狀況;修正的原則是:附加檢查出問題時,寧可放行並註記「需人工確認」,也不能讓整張訂單無聲消失。表單防護也一樣,擋下時要做到三件事:
- 在頁面上講清楚,不要用彈出視窗或空白頁。本站擋下時顯示頁內訊息,說明「這次送出沒有通過驗證」,請客人重新整理再送一次,並附上免付費專線 0800-670000 與線上諮詢的連結。逾時與送太多次這兩種情況,訊息各自寫明原因。
- 每次擋下都留紀錄。紀錄要寫原因,才看得出是哪一道在擋、有沒有擋錯人;上一節的統計就是從這裡來的。
- 定期回頭看。CSRF 不符或頻率限制的筆數突然變多,先查是不是頁面快取把舊 token 一起存起來、或是同一個辦公室的人在同一段時間集中送出,再決定要不要調整。
找廠商做表單時,問這 7 件事
一、只接受 POST 嗎?直接開啟處理程式的網址會怎樣?二、有沒有 CSRF token,工作階段 cookie 有沒有設 HttpOnly、Secure、SameSite?三、有沒有蜜罐欄位,藏法會不會被報讀軟體或自動填入誤填?四、有沒有停留時間檢查?五、頻率限制用什麼判斷來源位址?六、擋下時客人看到什麼,有沒有電話等替代管道?七、擋下紀錄放在哪裡、誰會看?
這 7 個問題可以直接寫進需求書的功能欄位,寫法見網站建置需求書怎麼寫;報價時表單屬於「基本」功能級別,但防護做到哪裡要寫清楚,見形象網站製作費用怎麼算。用 WordPress 的網站,表單外掛的防護設定也要跟著更新紀律一起管,被入侵後的處理見WordPress 被駭怎麼救。
本站三張表單共用同一支防護程式,新增表單時只要在表單頁與處理頁各呼叫一次,兩邊沒有成對就一律擋下,寧可擋錯也不留沒防護的入口。這種做法適合在建站時就一起規劃:網頁設計階段把表單防護、通知信與 GA4 事件一起定義,上線後由網站代管定期看擋下紀錄。瑪尼國際成立於 2004 年,深耕逾 20 年、服務逾 500 家企業,網站設計、主機與上線後的維護由同一組人負責,這就是我們的一條龍服務。
常見問題
Q:官網表單垃圾訊息一定要加驗證碼才擋得住嗎?
不一定。多數自動化的垃圾訊息,用蜜罐欄位、停留時間檢查、CSRF token 與頻率限制就能擋下,這四道對真人完全看不見,不會多一個填寫步驟。驗證碼會讓每一位真客戶多一道關卡,通常還要載入第三方服務,建議四道都做了、垃圾訊息仍持續進來,再把驗證碼加在最後一關。
Q:表單的蜜罐欄位是什麼?會不會擋到真人?
蜜罐是一個用 CSS 移出畫面、人看不到的文字欄位。真人不會填它,自動填表程式通常會把所有欄位都填滿,只要這個欄位有值就判定為機器人。為了避免誤擋,要同時讓螢幕報讀軟體略過它、不讓 Tab 鍵跳進去,並關閉瀏覽器自動填入。
Q:表單防護擋到真客戶的詢價怎麼辦?
擋下時不要只顯示錯誤代碼或空白頁,要在頁面上說明原因,並附上電話與其他聯絡管道,讓客人改用別的方式聯絡。同時把每次擋下的原因寫進紀錄,定期檢查有沒有真人被擋,再調整檢查的順序與門檻。