Zum Inhalt springen

Sicherheit

Zwei Authentifizierungsmechanismen:

TypBeschreibungLebensdauer
JWTKurzlebige Tokens via @fastify/jwtSession-basiert
API-KeyDauerhafter Key via X-API-Key HeaderBis zum Widerruf

Das authenticate-Decorator prüft beide Varianten — zuerst JWT, dann API-Key als Fallback.

JWT-Tokens in URL-Query-Parametern werden in Server-Logs automatisch als token=*** maskiert.

  • API-Key Generierung und Widerruf: max. 5 Anfragen pro Stunde
  • KI-Rezeptüberarbeitung: max. 5 Anfragen pro 15 Minuten

Bei der KI-Rezeptüberarbeitung werden Nutzer-Eingaben in Delimiter-Blöcke eingebettet und dürfen nur als inhaltliche Anweisung interpretiert werden. Der System-Prompt weist die KI explizit an, Anweisungen außerhalb des Rezept-Kontexts zu ignorieren. Der KI-Output wird durch sanitizeAiRecipe() sanitiert (Längenlimits, Typ-Validierung, Wertebereichsprüfung) und zusätzlich strukturell validiert (mind. 1 Zutat, 1 Zubereitungsschritt, nicht-leerer Titel).

Unique-Index auf api_key (WHERE NOT NULL) für schnelle Lookups und Eindeutigkeit.

Das Tampermonkey-Userscript escaped alle Fehlermeldungen (escapeHtml()) bevor sie ins DOM eingefügt werden.

  • @connect-Einschränkung — Userscript darf nur mit dem konfigurierten API-Host kommunizieren (kein @connect *)
  • GM_setValue — Konfiguration in Tampermonkey-Storage statt in localStorage der REWE-Domain

Bring!-Passwörter werden AES-256-GCM-verschlüsselt in der SQLite-Datenbank gespeichert.

requireAdmin nutzt das zentrale authenticate-Decorator (API-Key-kompatibel) statt direktem jwtVerify.

Alle Haushalt-bezogenen Endpunkte prüfen die Mitgliedschaft über isHouseholdMember(). Der resolveHousehold-Decorator:

  1. Authentifiziert den Benutzer (JWT oder API-Key)
  2. Liest den X-Household-Id-Header
  3. Validiert die Mitgliedschaft — bei ungültigem Haushalt gibt es 403 Forbidden
  4. Setzt request.householdId für alle nachfolgenden Queries

Da die native EventSource-API keine Custom-Header unterstützt, wird das JWT-Token als Query-Parameter (?token=...) akzeptiert. Das Token wird serverseitig manuell via fastify.jwt.verify() geprüft.

  • 8 Zeichen, alphanumerisch, mittels crypto.randomBytes() generiert
  • 48 Stunden gültig, danach nicht mehr verwendbar
  • Einmalverwendung — nach erfolgreichem Beitritt nicht erneut nutzbar
  • 32 Byte, hex-encoded (crypto.randomBytes(32))
  • 7 Tage gültig (konfigurierbar per expires_days-Parameter)
  • Öffentlicher Zugriff zeigt nur Rezeptdaten — keine sensiblen Felder (User-ID, Haushalt-ID etc.)