// docs / baas security / clerk hardening
Clerk セキュリティチェックリスト: 20 項目
Clerk はあなたのアプリの認証、セッション、組織を処理します — つまり、設定ミスの Clerk 統合は認証バイパス、セッション固定ベクトル、または組織漏洩経路です。このチェックリストは、キー、セッション設定、Webhook、組織、JWT テンプレート、継続的監視にわたる 20 項目の監査です。AI コーディングツールは妥当なデフォルトで素早く Clerk を配線します。このリストはそれらが残す項目をキャッチします。
認証層の設定ミスが AI ツールの弱点である理由の背景についてはAI コーディングツールがセキュリティギャップを残す理由を参照してください。Auth0 の並行チェックリストについてはAuth0 セキュリティチェックリストを参照してください。
環境キーとオリジン許可リスト
Clerk はプロジェクトごとに 2 つの異なるキーを発行します。それらを混在させたり漏洩させたりすることが最初の失敗モードです。
- 公開可能キー (本番では
pk_live_*、開発ではpk_test_*) をブラウザで使用し、シークレットキー (sk_live_*/sk_test_*) はサーバーのみで使用する。 公開可能キーはNEXT_PUBLIC_CLERK_PUBLISHABLE_KEYで安全です。シークレットキーは決して公開 env プレフィックスを持ってはならず、クライアントコンポーネントに決して現れてはいけません。 - 本番アプリが
pk_test_*ではなくpk_live_*を使用していることを確認。 テストインスタンスは未検証のメールアドレスと無効化された MFA を許可します — 本番にテストモードを出荷することは認証バイパスです。 - Clerk ダッシュボードで許可されたオリジンを構成。 Settings → Domains → Allowed origins は本番ドメインを正確にリストしなければなりません。空またはワイルドカードのオリジンリストは、攻撃者があなたのバックエンドと通信するなりすまし Clerk フロントエンドを作成することを許します。
- 離職または漏洩疑いがあればシークレットキーをローテーション。 Dashboard → API Keys → Reset。旧キーは無効化されます。ローテーションの前に新しい値でサーバー側コードを再デプロイします。
セッション構成
セッション有効期限とアイドルタイムアウトは、盗まれたセッションが 10 分のインシデントになるか 30 日のインシデントになるかの違いです。
- 機密データを扱う SaaS アプリでは、セッション非アクティビティタイムアウトを 30 分以下に設定。 Dashboard → Sessions → Inactivity timeout。銀行クラスのアプリは 5〜10 分、標準 SaaS は 30〜60 分、コンシューマーアプリは 1〜7 日を使用すべきです。デフォルトは 7 日です。
- パスワード変更、メール変更、MFA 登録時のセッション失効を有効化。 Dashboard → Sessions → Revoke on。これらはユーザー起点のセキュリティイベントです。他のデバイス上の既存セッションは終了させるべきです。
- サインイン時だけでなく、保護されたすべてのルートでサーバー側のセッション検証を行う。 Next.js では: サーバーコンポーネント / API ルートで
const { userId } = await auth();がクッキーから JWT を読み、検証します。クッキーのみのチェックを決して信頼しないでください。 - セッションクッキーに
SameSite=Lax(デフォルト) またはStrictを設定。 DevTools → Application → Cookies で確認します。SameSite=Noneは CSRF ベクトルです — クロスドメイン認証を明示的に構成していない限り、決して使用しないでください。
Webhook 検証
Clerk Webhook はユーザーライフサイクルイベント (作成、更新、削除、session.ended) で発火します。これらはあなたのデータベースの同期メカニズムであり — 偽造された Webhook はデータベース書き込みプリミティブです。
- すべての Webhook で Svix 署名を検証。 Clerk Webhook は Svix で署名されます。
new Webhook(secret).verify(body, headers)を使用します。検証に失敗したら401で拒否します。 - Webhook シークレットを環境変数に格納し、コードに格納しない。 シークレットはダッシュボード再生成のたびにローテーションします — デプロイは定数からではなく env から読まなければなりません。
- すべてのハンドラで冪等性。 Webhook 配信は繰り返される可能性があります。
webhook_eventsテーブルでsvix-idヘッダを主キーとして使って重複排除します。状態変更と冪等性インサートを同じトランザクションでラップします。 user.deletedで、PII を 24 時間以内にハード削除または匿名化。 GDPR / CCPA がそれを要求します。削除パスを監査します: このユーザーのデータはどのテーブルが保持していますか? 可能なら FK ON DELETE CASCADE を使用します。
組織と権限
Clerk Organizations を使用する場合、組織境界はあなたのテナント分離です。すべてのサーバー側クエリはそれでフィルタする必要があります。
- すべての API ルートで、
auth()からuserIdとorgIdの両方を読み、データベースクエリを両方でフィルタする。WHERE org_id = $orgId AND user_id = $userId。リクエストボディからのorg_idを決して信頼しないでください。 - 特権操作には、ユーザーオブジェクトに対する boolean チェックではなく Clerk ロールチェックを使用。
has({ role: 'org:admin' })は検証済み JWT からロールを読みます。ユーザーは古いクライアントオブジェクトの boolean を偽造できますが、JWT クレームは偽造できません。 - 2 つの実際の組織アカウントでクロス組織分離をテスト。 組織 A を作成しデータを投入し、別ブラウザで組織 B にサインインし、API 経由で組織 A のデータを読もうとします。レスポンスは
403または404でなければなりません。
JWT テンプレートと外部統合
JWT テンプレートは Clerk アイデンティティを Supabase、Firebase、その他の下流サービスにプッシュします。設定ミスのテンプレートはクレームを過剰共有するか、意図しないデータを公開します。
- 各 JWT テンプレートで、すべてのクレームをリストし必要性を確認。 Dashboard → JWT Templates。
emailとphoneを Supabase に送るテンプレートは、ブラウザで JWT を読む誰にでも PII を露出します。 - クライアント側下流呼び出しで使用される 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.
