// 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を決して信頼しないでください。 - <strong>Use Clerk role checks for privileged operations, not boolean checks against the user object.</strong> <code>has({ role: 'org:admin' })</code> reads the role from the verified JWT. A user can spoof a boolean on a stale client object; they cannot spoof a JWT claim.
- 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 エクスポートを最後の既知の良好なコピーと差分します。
次のステップ
本番 URL に対して FixVibe スキャンを実行してください — baas.clerk-auth0 チェックは Clerk 公開可能キー、本番のテストキー、バンドルされたシークレットキーをフラグします。Auth0 の同等チェックリストについてはAuth0 セキュリティチェックリストを参照してください。BaaS プロバイダ横断の全体像についてはBaaS 設定ミススキャナをお読みください。
