// docs / baas security / clerk hardening
Clerk 安全清單:20 項
Clerk 為你的應用程式處理驗證、工作階段與組織 — 這代表設定錯誤的 Clerk 整合就是驗證繞過、工作階段固定向量或組織外洩路徑。本清單是涵蓋金鑰、工作階段設定、webhook、組織、JWT 範本與持續監控的 20 項稽核。AI 編碼工具會以合理預設快速接好 Clerk;本清單捕捉它們留下的項目。
關於驗證層設定錯誤為何是 AI 工具弱點的背景,請參閱 AI 編碼工具為何留下安全漏洞。關於 Auth0 上的對應清單,請參閱 Auth0 安全清單。
環境金鑰與來源允許清單
Clerk 為每個專案發行兩種不同的金鑰。混淆或洩漏它們是第一個失敗模式。
- 在瀏覽器中使用可公開金鑰 (生產為
pk_live_*、開發為pk_test_*);僅在伺服器端使用機密金鑰 (sk_live_*/sk_test_*)。可公開金鑰在NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY中是安全的;機密金鑰絕不能帶有公開的 env 前綴,也絕不能出現在用戶端元件中。 - 驗證生產應用程式使用
pk_live_*,而非pk_test_*。測試執行個體允許未驗證的電子郵件地址與停用的 MFA — 將測試模式發布到生產就是一種驗證繞過。 - 在 Clerk 儀表板中設定允許的來源。Settings → Domains → Allowed origins 必須精確列出你的生產網域。空白或萬用字元的來源清單會讓攻擊者能建立與你後端通訊的假冒 Clerk 前端。
- 在任何離職或疑似洩漏時輪換機密金鑰。儀表板 → API Keys → Reset。舊金鑰失效;在輪換生效前以新值重新部署伺服器端程式碼。
工作階段設定
工作階段過期與閒置逾時是被竊工作階段為 10 分鐘事件還是 30 天事件的差別。
- 對處理敏感資料的 SaaS 應用程式,將工作階段閒置逾時設為 30 分鐘或更短。儀表板 → Sessions → Inactivity timeout。銀行等級的應用程式應使用 5-10 分鐘;標準 SaaS 為 30-60 分鐘;消費性應用程式為 1-7 天。預設為 7 天。
- 在密碼變更、電子郵件變更與 MFA 註冊時啟用工作階段撤銷。儀表板 → Sessions → Revoke on。這些是使用者主動發起的安全事件;其他裝置上的現有工作階段應被終止。
- 在每條受保護路由上於伺服器端驗證工作階段,而不僅在登入時。在 Next.js 中:伺服器元件 / API 路由中的
const { userId } = await auth();會從 cookie 讀取 JWT 並驗證它。絕不要只信任 cookie 檢查。 - 在工作階段 cookie 上設定
SameSite=Lax(預設) 或Strict。在 DevTools → Application → Cookies 中驗證。SameSite=None是 CSRF 向量 — 除非你已明確設定跨網域驗證設定,否則絕不要使用。
Webhook 驗證
Clerk webhook 會在使用者生命週期事件 (created、updated、deleted、session.ended) 上觸發。它們是你資料庫的同步機制 — 而偽造的 webhook 就是一種資料庫寫入原語。
- 對每個 webhook 驗證 Svix 簽章。Clerk webhook 由 Svix 簽署。使用
new Webhook(secret).verify(body, headers)。驗證失敗時以401拒絕。 - 將 webhook 機密存於環境變數,絕不在程式碼中。機密會在每次儀表板重新產生時輪換 — 你的部署必須從 env 讀取它,而非從常數。
- 每個處理程式都要具備冪等性。Webhook 投遞可能重複。在
webhook_events資料表中使用svix-id標頭作為主鍵以進行去重複。將狀態變更與冪等插入包進同一筆交易。 - 在
user.deleted上,24 小時內硬刪除或匿名化 PII。GDPR / CCPA 都要求這樣做。稽核刪除路徑:哪些資料表持有此使用者的資料?在能用的地方使用 FK ON DELETE CASCADE。
組織與權限
如果你使用 Clerk Organizations,組織邊界就是你的租戶隔離。每個伺服器端查詢都必須以它過濾。
- 在每條 API 路由上,從
auth()讀取userId與orgId,並以兩者過濾資料庫查詢。WHERE org_id = $orgId AND user_id = $userId。絕不要信任來自請求主體的org_id。 - 對特權操作使用 Clerk 角色檢查,而非對使用者物件做布林檢查。
has({ role: 'org:admin' })會從已驗證的 JWT 讀取角色。使用者可以在過期的用戶端物件上偽造布林值;但他們無法偽造 JWT 宣告。 - 以兩個真實組織帳號測試跨組織隔離。建立組織 A、填入資料、在另一個瀏覽器中以組織 B 登入,嘗試透過 API 讀取組織 A 的資料。回應必須是
403或404。
JWT 範本與外部整合
JWT 範本將 Clerk 身分推送到 Supabase、Firebase 與其他下游服務。設定錯誤的範本會過度共享宣告或暴露你並不打算暴露的資料。
- 對每個 JWT 範本,列出每個宣告並確認其必要性。儀表板 → JWT Templates。一個會把
email和phone傳給 Supabase 的範本,會將 PII 暴露給任何能在瀏覽器中讀到 JWT 的人。 - 對用於用戶端下游呼叫的 JWT 範本設定短的過期時間。下游 API 請求 60 秒是標準。長壽的 JWT 會被竊取並重放。
- 在接收端驗證對象 (
aud) 宣告。Supabase、Firebase 等應檢查aud是否符合預期的服務識別碼。若沒有這項檢查,為服務 A 發行的 JWT 可以驗證至服務 B。
營運監控
驗證是你擁有的最高訊號日誌來源。要監視它。
- 對每 IP / 每帳號的登入失敗激增告警。正常失敗率的 50 倍就是憑證填充攻擊。Clerk 會將這些事件發送到 webhook;將它們路由到你的 SIEM。
- 每季檢視工作階段與執行個體設定的漂移。隨著 Clerk 更新,預設值會變;「舊設定」會隨時間悄悄變成錯誤。將儀表板 JSON 匯出與你最後已知正確的副本進行差異比較。
後續步驟
Run a FixVibe scan against your production URL — it flags Clerk test keys in production and secret keys bundled into JavaScript. For the equivalent checklist on Auth0, see Auth0 security checklist. For the umbrella view across BaaS providers, read BaaS misconfiguration scanner.
