起點:一個錯誤的安全模型

v3.1 freemium 系統用的是純前端 Crockford 授權碼 —— 驗證邏輯全在瀏覽器, 任何人打開 DevTools 都能繞過。問題不是「前端被看到」,而是 沒有任何後端在驗證

五個 Stage 的改造

Stage內容
1 · Worker JWT建立 Cloudflare Worker,HS256 + WebCrypto;端點 /health、/license/issue、/license/validate
2 · v3.2 模組化index.html -334 行,抽出 5 個 JS 模組,純前端 Crockford 換成 JWT
3 · v3.2.1 KV-backed引入 KV namespace;/issue 要求 KV status='active' 才簽;/validate 每次查 KV;JWT 1 年→7 天 + 自動續期
4 · v3.3.0 Sandbox第二個 Sandbox Worker + KV;前端 ?sandbox=1 切換;PayPal SDK 動態載入
5 · v3.3.1 retry fix修正 webhook 時序:對「403 + currentStatus='pending'」也 retry

最終驗證(Sandbox e2e)

訂閱 I-R2SFXX7U1SW2:建立 → ACTIVATED → KV active; 取消 → CANCELLED webhook → KV cancelled;4 秒後 /license/validate 回 401。 即時撤銷成立。

關鍵教訓

「開源 vs. 收費」是迷思。前端被看到不是問題,後端驗證才是。架構正確時,整個前端公開都沒事。

JWT 短期 + KV 撤銷 vs 純 JWT 長期:訂閱系統必須前者才能即時撤銷。

Sandbox 是必需的,不是 nice-to-have —— 台灣 PayPal P2P 限制讓真實 Live 自我測試不可能。

base64UrlEncode 對 binary buffer:要逐 byte 從 Uint8Array 構造,別把 ArrayBuffer 轉字串再 btoa(會被當 UTF-8 雙重編碼)。

來源:個人開發日誌 2026-05-14(v3.2 → v3.3.1)· 3 commits · 2 Worker · 2 KV namespace · 5 個攻擊向量已防禦