
✨ 第一眼的愛:Bookmarklet 其實是超好用的小工具
一開始,我是站在「使用者」那一邊。
情境大概是這樣:
露營區的預訂頁面有一整排欄位:入住日期、營位數量、露營天數......每次開放新月份,手動填一遍,怎麼看都很浪費時間。
於是我寫了一顆 bookmarklet:
- 一點就自動填好:
- 入住日期
- 營位數量(例如 6 個)
- 露營天數(例如 2 天)
- 最後順手幫我按下「進行營位預訂」
從使用者體感來看,這顆小工具做了兩件事:
- 把「填表」變成一鍵行為
- 把「搶時間」的動作極限壓縮
然而,隨著測試深入,問題不再是「怎麼填得更快」,而是------如果我是網站端,要怎麼面對這種工具?
🧩 一個轉折:當 bookmarklet 遇上「限制日期區間」的後端規則
預訂頁面其實會限制日期,例如:
min="2025-11-28"
max="2026-01-31"
Bookmarklet 雖然能填入任何字串,但:
- 前端會檢查一次
- 後端一定會再檢查
- 不合法資料無法成為有效訂單
那一刻我意識到:
Bookmarklet 能加速合法操作,但不能突破規則。
🧱 第二個身分:網站設計者眼中的「反 bookmarklet」難題
換位思考後,我發現了一個核心現實:
要完全阻止 bookmarklet 不可能。
但可以讓它「難用」或「無法突破真正的規則」。
因此,後端必要且不可省略。
前端能做的,是「提高腳本的成本」。
以下從簡單到複雜列出前端能做的事情。
🪜 從簡單到困難:前端世界裡的「反 bookmarklet 策略」
① 最基礎:前端驗證只是「體驗」
常見做法:
-
min/max
-
required
- 前端 change 檢查
但 bookmarklet 能:
- 直接改 value
- 呼叫送出的函式
- 甚至避開 UI、直接打 API
所以這層只是友善提醒,不是防線。
② lazy render:點擊後才渲染 <option>
作法:
-
<select> 初始沒有真正選項
- 使用者「點開」時才動態產生
這讓:
- 腳本硬寫
.options、固定 selector 失效
- DOM 結構在未操作前不完整
③ 客製 dropdown + hidden input
把 UI 與資料分開:
- UI 讓使用者選
- 真實送出的值在 hidden input
腳本就算改 UI,也不一定改到真正送出的欄位。
④ 狀態機(State Machine):流程必須照順序
流程例子:
- 日期 →
- 營位數量 →
- 露營天數 →
- READY → 才能送出
改 value 不等於完成流程。
若 bookmarklet 沒依序觸發事件,前端狀態就不會到 READY。
⑤ 行為特徵(Behavior):看起來像人還是像腳本?
可觀察:
- 有沒有滑鼠移動
- 有沒有點擊
- 有沒有 focus/blur
- 三欄完成時間是否合理
- 操作順序是否正常
以此產生一個「人類分數」,太低就不送出。
⑥ 亂數 DOM / 動態結構
手段:
- 動態 ID
- 隨載入變化的 class
- 操作前不渲染完整 DOM
目的:
⑦ 一次性 Token:流程沒走完就算填對也不能送
方法:
- 每步驟更新 token
- 最後送出時必須配對正確流程 token
- token 用過立即失效
提升了腳本的流程模擬成本。
🧭 最後的轉念:設計「不怕」 bookmarklet 的系統
結論整理:
- Bookmarklet 是很好的微自動化工具。
- 真正重要的是後端驗證,而不是 DOM 是否被改。
- 前端能做的多是「增加難度」。
- 真正想攻擊的會直接走 API,不會在 UI 裡掙扎。
🧰 給自己的 GPT 提問範本(Prompts)
- 分析 bookmarklet 風險
- 設計前端狀態機流程
- 行為特徵模型
- 動態 DOM 策略
- 前後端驗證分工