FixVibe

// docs / baas security / clerk hardening

Clerk-Sicherheits-Checkliste: 20 Punkte

Clerk handhabt Auth, Sessions und Organisationen für deine App — was bedeutet, dass eine falsch konfigurierte Clerk-Integration ein Auth-Bypass, ein Session-Fixierungs-Vektor oder ein Org-Leakage-Pfad ist. Diese Checkliste ist ein 20-Punkte-Audit über Keys, Session-Konfig, Webhooks, Organisationen, JWT-Templates und laufendes Monitoring. KI-Coding-Tools verdrahten Clerk schnell mit vernünftigen Defaults; diese Liste fängt die Punkte, die sie auf dem Tisch liegen lassen.

Für Hintergrund, warum Fehlkonfigurationen auf Auth-Ebene eine Schwäche von KI-Tooling sind, siehe Warum KI-Coding-Tools Sicherheitslücken hinterlassen. Für die parallele Checkliste zu Auth0 siehe Auth0-Sicherheits-Checkliste.

Umgebungs-Keys und Origin-Allowlist

Clerk stellt zwei verschiedene Keys pro Projekt aus. Sie zu verwechseln oder zu leaken ist der erste Fehlermodus.

  1. Verwende den Publishable-Key (pk_live_* in Produktion, pk_test_* in Dev) im Browser; verwende den Secret-Key (sk_live_* / sk_test_*) nur auf dem Server. Der Publishable-Key ist in NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY sicher; der Secret-Key darf niemals ein öffentliches Env-Präfix tragen und niemals in einer Client-Komponente erscheinen.
  2. Verifiziere, dass die Produktions-App pk_live_* verwendet, nicht pk_test_*. Test-Instanzen erlauben unverifizierte E-Mail-Adressen und deaktiviertes MFA — Test-Mode in Produktion auszuliefern ist ein Auth-Bypass.
  3. Konfiguriere die erlaubten Origins im Clerk-Dashboard. Settings → Domains → Allowed origins muss deine Produktionsdomain exakt listen. Leere oder Wildcard-Origin-Listen erlauben Angreifern, betrügerische Clerk-Frontends zu bauen, die mit deinem Backend sprechen.
  4. Rotiere den Secret-Key bei jedem Abgang oder Verdacht auf Leak. Dashboard → API Keys → Reset. Alter Key wird invalidiert; deploye serverseitigen Code mit dem neuen Wert vor der Rotation.

Session-Konfiguration

Session-Ablauf und Idle-Timeouts sind der Unterschied zwischen einer gestohlenen Session als 10-Minuten-Vorfall und einem 30-Tage-Vorfall.

  1. Setze den Session-Inaktivitäts-Timeout auf 30 Minuten oder weniger für SaaS-Apps, die sensible Daten verarbeiten. Dashboard → Sessions → Inactivity timeout. Bank-Tier-Apps sollten 5-10 Minuten verwenden; Standard-SaaS 30-60 Minuten; Consumer-Apps 1-7 Tage. Default ist 7 Tage.
  2. Aktiviere Session-Widerruf bei Passwortänderung, E-Mail-Änderung und MFA-Anmeldung. Dashboard → Sessions → Revoke on. Das sind nutzerinitiierte Sicherheitsereignisse; bestehende Sessions auf anderen Geräten sollten beendet werden.
  3. Verifiziere Sessions serverseitig auf jeder geschützten Route, nicht nur beim Sign-in. In Next.js: const { userId } = await auth(); in einer Server-Komponente / API-Route liest das JWT aus dem Cookie und validiert es. Vertraue niemals einer reinen Cookie-Prüfung.
  4. Setze SameSite=Lax (Default) oder Strict auf dem Session-Cookie. Verifiziere in DevTools → Application → Cookies. SameSite=None ist ein CSRF-Vektor — verwende es nie, sofern du nicht explizit ein domainübergreifendes Auth-Setup konfiguriert hast.

Webhook-Verifizierung

Clerk-Webhooks feuern bei Lifecycle-Ereignissen des Nutzers (created, updated, deleted, session.ended). Sie sind der Synchronisierungsmechanismus für deine Datenbank — und ein gefälschter Webhook ist eine Schreib-Primitive für die Datenbank.

  1. Verifiziere die Svix-Signatur bei jedem Webhook. Clerk-Webhooks werden von Svix signiert. Nutze new Webhook(secret).verify(body, headers). Lehne mit 401 ab, wenn die Verifizierung fehlschlägt.
  2. Speichere das Webhook-Secret in einer Umgebungsvariablen, niemals im Code. Das Secret rotiert bei jeder Dashboard-Regeneration — dein Deploy muss es aus Env lesen, nicht aus einer Konstanten.
  3. Idempotenz in jedem Handler. Webhook-Zustellungen können sich wiederholen. Verwende den svix-id-Header als Primärschlüssel in einer webhook_events-Tabelle zur Deduplizierung. Wickle die Zustandsänderung und das Idempotenz-Insert in derselben Transaktion ab.
  4. Bei user.deleted PII binnen 24 Stunden hart löschen oder anonymisieren. GDPR / CCPA verlangen es. Auditiere den Löschpfad: welche Tabellen halten die Daten dieses Nutzers? Verwende FK ON DELETE CASCADE, wo möglich.

Organisationen und Berechtigungen

Wenn du Clerk Organizations nutzt, ist die Org-Grenze deine Tenant-Isolation. Jede serverseitige Query muss danach filtern.

  1. Lies auf jeder API-Route sowohl userId als auch orgId aus auth() und filtere Datenbank-Queries nach beidem. WHERE org_id = $orgId AND user_id = $userId. Vertraue nie einer org_id aus dem Request-Body.
  2. Verwende Clerk-Rollenprüfungen für privilegierte Operationen, nicht Boolean-Prüfungen gegen das User-Objekt. has({ role: 'org:admin' }) liest die Rolle aus dem verifizierten JWT. Ein Nutzer kann ein Boolean auf einem veralteten Client-Objekt fälschen; einen JWT-Claim kann er nicht fälschen.
  3. Teste die Cross-Org-Isolation mit zwei echten Org-Konten. Erstelle Org A, befülle Daten, melde dich in Org B in einem anderen Browser an, versuche, die Daten von Org A über die API zu lesen. Antwort muss 403 oder 404 sein.

JWT-Templates und externe Integrationen

JWT-Templates schieben Clerk-Identität in Supabase, Firebase und andere nachgelagerte Dienste. Falsch konfigurierte Templates teilen Claims über das Nötige hinaus oder legen Daten offen, die du nicht meintest.

  1. Liste für jedes JWT-Template jeden Claim auf und bestätige, dass er notwendig ist. Dashboard → JWT Templates. Ein Template, das email und phone an Supabase sendet, legt PII jedem offen, der das JWT im Browser liest.
  2. Setze eine kurze Ablaufzeit auf JWT-Templates, die für clientseitige Downstream-Calls verwendet werden. 60 Sekunden für Downstream-API-Requests ist Standard. Längerlebige JWTs werden gestohlen und replayed.
  3. Verifiziere den Audience-Claim (aud) auf der empfangenden Seite. Supabase, Firebase, etc. sollten prüfen, dass aud dem erwarteten Service-Identifier entspricht. Ohne das kann ein für Service A ausgestelltes JWT sich gegen Service B authentifizieren.

Operatives Monitoring

Auth ist die signalstärkste Log-Quelle, die du hast. Beobachte sie.

  1. Alarmiere bei Spikes fehlgeschlagener Logins pro IP / pro Konto. Eine 50× normale Fehlerrate ist ein Credential-Stuffing-Angriff. Clerk emittiert diese Ereignisse an Webhooks; route sie an dein SIEM.
  2. Quartalsweise Überprüfung der Drift von Session- und Instance-Einstellungen. Defaults ändern sich mit Clerk-Updates; „alte Konfigurationen" werden mit der Zeit lautlos falsch. Vergleiche den JSON-Export des Dashboards mit deiner letzten bekannt-guten Kopie.

Nächste Schritte

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.

// scanne deine baas-oberfläche

Finde die offene Tabelle, bevor es jemand anderes tut.

Gib eine Produktions-URL ein. FixVibe ermittelt die BaaS-Anbieter, mit denen deine App spricht, identifiziert ihre öffentlichen Endpunkte und meldet, was ein nicht authentifizierter Client lesen oder schreiben kann. Kostenlos, ohne Installation, ohne Karte.

  • Kostenloser Tarif — 3 Scans pro Monat, ohne Anmeldekarte.
  • Passives BaaS-Fingerprinting — keine Domain-Verifizierung erforderlich.
  • Supabase, Firebase, Clerk, Auth0, Appwrite und mehr.
  • Coding-agent prompts where code/config applies, plus provider-console steps for hosted BaaS fixes.
Kostenlosen BaaS-Scan starten →

keine anmeldung erforderlich

Clerk-Sicherheits-Checkliste: 20 Punkte · FixVibe