Das Kit wird mit einer Defense-in-Depth-Sicherheitsarchitektur ausgeliefert, die deine Anwendung auf mehreren Ebenen schützt. Jede API-Anfrage durchläuft Rate Limiting, Eingabevalidierung, Sanitization, Security-Headers und CORS — alles vorkonfiguriert und produktionsbereit.
Diese Seite gibt dir einen Überblick über die Architektur. Für Implementierungsdetails siehe Rate Limiting & Validierung und Headers & CORS.
Defense-in-Depth-Architektur
Sicherheit ist in fünf konzentrischen Schichten implementiert. Ein Angriff muss alle Schichten überwinden, um erfolgreich zu sein — wird er von einer einzigen Schicht abgefangen, wird die Anfrage blockiert:
┌─────────────────────────────────────────────────────────────┐
│ Layer 1: Middleware │
│ CORS preflight, Clerk authentication, security headers │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Layer 2: Rate Limiting │ │
│ │ Category-based limits (upload, email, payments) │ │
│ │ │ │
│ │ ┌─────────────────────────────────────────────┐ │ │
│ │ │ Layer 3: Input Validation │ │ │
│ │ │ Zod schemas for every API endpoint │ │ │
│ │ │ │ │ │
│ │ │ ┌─────────────────────────────────────┐ │ │ │
│ │ │ │ Layer 4: Sanitization │ │ │ │
│ │ │ │ XSS, SQL, path traversal, URLs │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ │ ┌─────────────────────────────┐ │ │ │ │
│ │ │ │ │ Layer 5: Error Handling │ │ │ │ │
│ │ │ │ │ Safe responses, no leaks │ │ │ │ │
│ │ │ │ └─────────────────────────────┘ │ │ │ │
│ │ │ └─────────────────────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
Jede Schicht arbeitet unabhängig — sie sind nicht aufeinander angewiesen. Das bedeutet: Wird Rate Limiting deaktiviert (z. B. in der lokalen Entwicklung ohne Redis), schwächt das weder die Eingabevalidierung noch die Security-Headers.
Middleware-Chain
Jede Anfrage, die deine Anwendung erreicht, durchläuft die in
middleware.ts definierte Middleware-Chain. Die Chain wird in einer bestimmten Reihenfolge ausgeführt, wobei jeder Schritt die Anfrage kurz schließen kann:Incoming Request
|
v
1. Test Environment Check
|--- Test/CI? ──> NextResponse.next() (bypass all security)
|
v
2. CORS Preflight
|--- OPTIONS request? ──> Return 204 with CORS headers (stop here)
|
v
3. Clerk Authentication
|--- Public route? ──> Continue (auth state available but not required)
|--- Protected route? ──> auth.protect() (redirect to /login if unauthenticated)
|
v
4. Security Headers
|--- Apply HSTS, X-Frame-Options, CSP, Permissions-Policy, etc.
|
v
5. CORS Response Headers
|--- Add Access-Control-Allow-Origin and related headers
|
v
Response
Die Middleware ist für ausfallsicheren Betrieb ausgelegt. Wirft ein Schritt einen Fehler, gibt der Catch-Block
NextResponse.next() zurück, um legitime Anfragen nicht zu blockieren:src/middleware.ts — Fail-safe middleware entry
// Main middleware function with security enhancements
async function middleware(request: NextRequest) {
// Always bypass in test/CI environments
if (isTestEnvironment()) {
return NextResponse.next()
}
Clerk und Security-Headers werden über dynamische
import()-Aufrufe innerhalb der Middleware-Funktion geladen. Das verhindert, dass schwere Abhängigkeiten auf der obersten Ebene gebündelt werden, und ermöglicht es der Middleware, fehlende Pakete elegant zu handhaben (z. B. beim Testen ohne installiertes Clerk).Öffentliche vs. geschützte Routen
Die Middleware unterscheidet zwischen öffentlichen Routen (für alle zugänglich) und geschützten Routen (Authentifizierung erforderlich). Öffentliche Routen sind als explizite Allowlist definiert:
src/middleware.ts — Public routes configuration
// Define public routes that don't require authentication
const isPublicRoute = createRouteMatcher([
'/login(.*)',
'/register(.*)',
'/privacy(.*)',
'/terms(.*)',
'/imprint(.*)',
'/payment/(.*)',
'/email-preview(.*)',
'/logout(.*)',
'/api/health(.*)',
'/api/pricing(.*)',
'/api/webhooks/lemonsqueezy(.*)',
'/api/webhooks/resend(.*)',
'/api/webhooks/clerk(.*)',
'/robots.txt',
'/sitemap.xml',
])
Routenkategorien
| Kategorie | Routen | Auth erforderlich | Hinweise |
|---|---|---|---|
| Legal | /privacy, /terms, /imprint | Nein | Rechtliche Pflichtseiten |
| Auth | /login, /register, /logout | Nein | Clerk verwaltet den Auth-Flow |
| Utility | /payment, /email-preview | Nein | Zahlungsabwicklung und E-Mail-Vorschauen |
| Public API | /api/health, /api/pricing | Nein | Offene Endpunkte |
| Webhooks | /api/webhooks/lemonsqueezy, /api/webhooks/resend, /api/webhooks/clerk | Nein | Extern signaturgeprüft |
| SEO | /robots.txt, /sitemap.xml | Nein | Suchmaschinen-Dateien |
| Dashboard | /dashboard/** | Ja | Alle Dashboard-Routen |
| Protected API | /api/** (nicht oben aufgeführt) | Ja | Alle anderen API-Endpunkte |
Jede Route, die nicht in der öffentlichen Liste steht, erfordert eine gültige Clerk-Session. Nicht authentifizierte Benutzer werden zu
/login weitergeleitet.Fail-Open-Philosophie
Das Sicherheitssystem des Kits ist darauf ausgelegt, graceful zu degradieren statt katastrophal zu versagen. Das ist eine bewusste Architekturentscheidung:
| Szenario | Verhalten | Begründung |
|---|---|---|
| Redis nicht verfügbar | Rate Limiting deaktiviert, Anfragen werden durchgelassen | Benutzer nicht wegen Infrastrukturproblemen blockieren |
| Clerk kann nicht geladen werden | Middleware wird übersprungen | App nicht unterbrechen, wenn der Auth-Dienst ausfällt |
| Security-Headers-Import schlägt fehl | Anfrage wird ohne Headers fortgesetzt | Headers sind eine Verteidigungsschicht, kein Gatekeeper |
| Rate-Limit-Prüfung wirft Fehler | Anfrage wird durchgelassen | Fail-Open ist für SaaS sicherer als Fail-Closed |
Error in any security layer?
|
├── Log warning (for monitoring)
|
└── Allow request to continue
(other layers still active)
Fail-Open bedeutet, dass deine Anwendung bei teilweisen Ausfällen verfügbar bleibt — aber es bedeutet auch, dass Sicherheitsschichten still degradieren können. Überwache in der Produktion immer Warnmeldungen wie
"Rate limiting disabled - Redis not available". Richte Alerts für diese Muster ein, damit du schnell auf Infrastrukturprobleme reagieren kannst.Die Begründung: Für eine SaaS-Anwendung ist das Blockieren legitimer zahlender Kunden ein schlimmeres Ergebnis als das vorübergehende Durchlassen einiger zusätzlicher Anfragen. Jede Schicht protokolliert Warnungen, wenn sie degradiert, damit du die Ursache erkennen und beheben kannst.
Sicheres Fehlerhandling
Die fünfte und innerste Schicht stellt sicher, dass Fehlerantworten niemals sensible Informationen preisgeben. Das Kit enthält
sanitizeErrorMessage(), das Stack-Traces, Datenbankverbindungsstrings und interne Details aus API-Antworten entfernt:Development (NODE_ENV=development):
Error: "Connection refused at postgres://user:pass@host:5432"
→ Returned as-is (helpful for debugging)
Production (NODE_ENV=production):
Error: "Connection refused at postgres://user:pass@host:5432"
→ Returned as: "An unexpected error occurred"
Known safe errors (any environment):
Error: "Validation failed: email is required"
→ Returned as-is (safe for users to see)
Fehler, die mit bekannten sicheren Präfixen beginnen (
Validation failed, Invalid, Required, Not found, Unauthorized, Forbidden), werden unverändert weitergegeben. Alle anderen Fehler werden in der Produktion durch eine generische Meldung ersetzt.OWASP-Abdeckung
Die Sicherheitsschichten des Kits adressieren die häufigsten Schwachstellen in Webanwendungen:
| OWASP-Kategorie | Kit-Schutz | Schicht |
|---|---|---|
| Injection (SQL, XSS, Command) | Zod-Validierung + Sanitization-Funktionen | 3 & 4 |
| Broken Authentication | Clerk-Middleware mit Routenschutz | 1 |
| Sensitive Data Exposure | Security-Headers (HSTS, no-sniff) + sichere Fehlermeldungen | 1 & 5 |
| Broken Access Control | Trennung öffentlicher/geschützter Routen + Clerk auth.protect() | 1 |
| Security Misconfiguration | Vorkonfigurierte Security-Headers + CORS | 1 |
| Cross-Site Scripting (XSS) | sanitizeHtml() + X-XSS-Protection-Header | 1 & 4 |
| Rate Limiting Abuse | Kategoriebasiertes Rate Limiting mit Upstash Redis | 2 |
Wichtige Dateien
| Datei | Zweck | Zeilen |
|---|---|---|
apps/boilerplate/src/middleware.ts | Middleware-Chain — CORS, Clerk Auth, Security-Headers | 172 |
apps/boilerplate/src/lib/security/api-rate-limiter.ts | Kategoriebasiertes Rate Limiting mit Upstash Redis | 349 |
apps/boilerplate/src/lib/security/rate-limit-middleware.ts | withRateLimit()-Middleware-Factory für API-Routen | 231 |
apps/boilerplate/src/lib/security/sanitization.ts | XSS-, Dateiname-, URL-, E-Mail-, SQL-, JSON-Sanitization | 342 |
apps/boilerplate/src/lib/security/security-headers.ts | Generierung von Security-Headers (HSTS, CSP, CORP, etc.) | 200 |
apps/boilerplate/src/lib/security/cors-middleware.ts | CORS-Konfiguration und Middleware | 216 |
apps/boilerplate/src/lib/validations/api-schemas.ts | Zentrale Zod-Schemas für alle API-Endpunkte | 208 |