Sicherheitsprüfung - Ergebnis #20

Closed
opened 2026-08-23 22:38:48 +00:00 by florian.wilde · 4 comments
Owner

Sicherheitsprüfung: qrcode-generator

Stand: 24. August 2026
Geprüfter Commit: 4e2d222e8611f01ed11b48bd7b1013cfbf6ced53
Methode: manuelle statische Codeprüfung, Abhängigkeits-Audit, Secret-Suche, Lint, TypeScript- und Produktions-Build-Prüfung. Kein Test gegen eine laufende Produktionsinstanz.

Kurzurteil

Die Anwendung hat eine überdurchschnittlich sorgfältige Sicherheitsbasis: zentrale serverseitige Autorisierung, parametrisierte Datenbankzugriffe über Prisma, starke Passwort-Hashes, gehashte Sitzungstoken, OIDC mit State/Nonce/PKCE, Upload-Signaturprüfung und sandboxartige Header bei der Dateiauslieferung. Im geprüften Stand ist sie trotzdem nicht bedenkenlos öffentlich bereitzustellen.

Der wichtigste Fehler liegt in der OIDC-Kontoverknüpfung: Ein fehlender email_verified-Claim wird als bestätigte E-Mail gewertet. Abhängig vom Identity Provider kann das die Übernahme eines bestehenden lokalen Kontos einschließlich eines Administratorkontos ermöglichen. Hinzu kommen gefährliche Auslieferungsvorgaben (AUTH_ENABLED=false), leicht auslösbare Kontosperren, umgehbare In-Memory-Drosselungen und ein Wettlauf beim ersten OIDC-Administrator.

Befunde

S1 – Hoch: OIDC verknüpft Konten auch ohne positiv bestätigte E-Mail

Betroffene Stelle: src/lib/auth/oidc.ts:326-330, verwendet in src/app/api/auth/oidc/callback/route.ts:94-119.

emailVerified wird als payload.email_verified !== false berechnet. Damit gelten nicht nur true, sondern auch ein fehlender Claim, null, 0 oder eine Zeichenkette als bestätigt. Findet die Callback-Route anschließend ein lokales Konto mit derselben E-Mail-Adresse, hängt sie die fremde OIDC-Identität (sub) an dieses Konto. Danach kann sich diese Identität als das lokale Konto anmelden.

Ausnutzbarkeit: Hoch, wenn der konfigurierte OIDC-Anbieter email_verified nicht liefert oder Benutzer ihre E-Mail-Adresse dort unzureichend kontrolliert setzen können. Das ID-Token selbst muss weiterhin gültig signiert sein; dies ist kein Angriff ohne Zugriff auf den IdP.

Auswirkung: Kontoübernahme, bei passender Adresse auch Instanz-Administratorrechte.

Behebung: Nur den booleschen Wert true akzeptieren:

emailVerified: payload.email_verified === true

Noch robuster: Für die automatische Verknüpfung zusätzlich eine explizite Konfigurationsfreigabe verlangen oder lokale und OIDC-Konten nur administrativ verknüpfen. Einen Test für fehlend, false, null, String und true ergänzen.

S2 – Hoch (Fehlkonfiguration): Authentifizierung ist standardmäßig ausgeschaltet

Betroffene Stellen: .env.example:16-22, docker-compose.yml:37-40.

Die Compose-Vorgabe startet mit AUTH_ENABLED=false. In diesem Modus erzeugt die Anwendung einen system-Akteur, der jede Berechtigung besitzt. Gleichzeitig veröffentlicht Compose Port 3000 auf allen Interfaces. Eine versehentlich öffentlich erreichbare Standardinstallation erlaubt damit jedem Besucher Verwaltung, Uploads sowie Anlegen, Ändern und Löschen aller Codes.

Ausnutzbarkeit: Unmittelbar, sobald der Host aus einem nicht vollständig vertrauenswürdigen Netz erreichbar ist.

Behebung: Fail-closed ausliefern: AUTH_ENABLED in Compose verpflichtend machen (${AUTH_ENABLED:?…}) oder standardmäßig true setzen. Für bewusst offenen Einzelplatzbetrieb eine deutlich benannte Option verwenden und beim Start eine auffällige Warnung protokollieren. Port standardmäßig an 127.0.0.1 binden oder einen vorgeschalteten TLS-Proxy dokumentiert voraussetzen.

S3 – Mittel: Jeder kann bekannte Konten gezielt aussperren

Betroffene Stelle: src/app/api/auth/route.ts (MAX_ATTEMPTS = 8, 15 Minuten Sperre).

Acht falsche Passwörter sperren das betroffene Konto für 15 Minuten. Es gibt keinen Nachweis, dass der Anfragende der Kontoinhaber ist. Ein Angreifer, der die Administratoradresse kennt, kann die Sperre wiederholt erneuern und so die Verwaltung praktisch dauerhaft blockieren. Die zusätzliche IP-Drosselung verhindert dies nicht; acht Versuche liegen unter ihrer Grenze von 20.

Auswirkung: Gezielter Denial-of-Service gegen einzelne Benutzer, besonders problematisch bei nur einem Administrator.

Behebung: Progressive Verzögerung statt harter Kontosperre bevorzugen; alternativ Sperren zusätzlich nach vertrauenswürdig ermittelter Quelladresse begrenzen, Admin-Wiederherstellung vorsehen und Ereignisse alarmieren. Niemals allein auf vom Client gelieferte Forwarded-Header vertrauen.

S4 – Mittel: Drosselungen lassen sich per X-Forwarded-For umgehen

Betroffene Stellen: src/lib/auth/throttle.ts:56-68, src/app/api/feedback/route.ts:61-70.

Die Anwendung übernimmt stets den ersten Wert aus X-Forwarded-For. Bei direkter Veröffentlichung (die mitgelieferte Compose-Konfiguration tut genau das) kann jeder Client diesen Header frei wählen. Dadurch lassen sich sowohl die Login-Bremse als auch die öffentliche Feedback-Bremse mit wechselnden Werten umgehen. Die Zähler sind außerdem nur pro Prozess gespeichert und verlieren bei Neustart oder horizontaler Skalierung ihre Wirkung.

Auswirkung: Erleichtertes Password-Spraying, Feedback-Spam und Datenbankwachstum. Die Kontosperre begrenzt Versuche pro bekanntem Konto, verhindert aber breites Spraying und Feedback-Fluten nicht zuverlässig.

Behebung: Einen festen Trust-Proxy-Modus einführen: Forwarded-Header nur von bekannten Proxy-Adressen akzeptieren, sonst die Socket-Adresse verwenden. Für mehrere Instanzen einen gemeinsamen, atomaren Zähler (z. B. Redis oder Datenbank) verwenden. Zusätzlich globale Obergrenzen und Body-/Request-Rate-Limits am Reverse Proxy setzen.

S5 – Mittel: Wettlauf erzeugt mehrere erste OIDC-Administratoren

Betroffene Stelle: src/app/api/auth/oidc/callback/route.ts:122-145.

Beim OIDC-Bootstrap werden user.count() === 0 und user.create() getrennt ausgeführt. Zwei gleichzeitig abgeschlossene erste Anmeldungen können beide istErster=true sehen und anschließend beide als Instanz-Administrator angelegt werden. Die lokale Passwort-Ersteinrichtung schützt denselben Ablauf bereits korrekt mit einer serialisierbaren Transaktion; der OIDC-Pfad tut dies nicht.

Ausnutzbarkeit: Nur auf einer frischen Installation und mit einer gültigen IdP-Identität, aber gerade der erste Administrator ist eine besonders empfindliche Vertrauensgrenze.

Behebung: Prüfung und Anlage wie im lokalen Setup in eine serialisierbare Transaktion legen und Serialisierungsfehler sicher wiederholen. Noch besser: Bootstrap durch ein einmaliges, serverseitiges Setup-Token oder eine vorab erlaubte Administratoridentität absichern.

S6 – Niedrig bis mittel: CSRF-/Proxy-Vertrauensmodell ist fragil

Betroffene Stellen: src/lib/http.ts:18-30, src/lib/auth/session.ts:60-65, src/lib/auth/oidc.ts:106-121.

Die Origin-Prüfung vergleicht nur origin.host, nicht das vollständige Origin-Tupel aus Schema, Host und Port, und bevorzugt ungeprüft X-Forwarded-Host. Auch das Secure-Flag der Sitzung vertraut X-Forwarded-Proto. Bei einem korrekt konfigurierten Reverse Proxy ist das meist ausreichend; bei direkter Exposition oder einem Proxy, der eingehende Forwarded-Header nicht überschreibt, entscheidet jedoch der Client über sicherheitsrelevante Werte.

Ein fehlender Origin-Header wird pauschal akzeptiert. Für klassische Browser-CSRF-Angriffe ist das oft vertretbar, lässt aber keinen Schutz gegen Clients zu, die den Header entfernen, und erschwert ein eindeutiges Sicherheitsversprechen.

Behebung: Explizite Liste vertrauenswürdiger öffentlicher Origins und Proxy-Hops konfigurieren. Für schreibende Cookie-authentifizierte Requests vollständigen Origin-Vergleich oder ein CSRF-Token verlangen. Forwarded-Header nur hinter einem bekannten Proxy auswerten. Secure primär aus einer verpflichtenden HTTPS-BASE_URL ableiten.

S7 – Niedrig: Bekannte High-Advisory in der Prisma-Toolchain

npm audit --omit=dev meldet GHSA-ggr8-5vv4-36mx in deepmerge-ts@7.1.5, transitiv über @prisma/config@7.9.1/prisma@7.9.1. Die Schwachstelle ist Stack-Erschöpfung beim Zusammenführen rekursiver Objektgraphen.

Die praktische Remote-Ausnutzbarkeit ist hier niedrig, weil Prisma-Konfiguration nicht aus HTTP-Eingaben erzeugt wird. Die Prisma-CLI wird jedoch in das Laufzeit-Image kopiert und beim Containerstart für Migrationen verwendet; daher sollte der Befund nicht einfach als reine Entwicklungsabhängigkeit ignoriert werden.

Behebung: Auf eine Prisma-Version aktualisieren, die deepmerge-ts >= 8 verwendet, sobald kompatibel verfügbar, und den Lockfile-Audit in CI erzwingen. Kein blindes npm audit fix --force auf Prisma 6 durchführen.

Härtungsempfehlungen

  • Die vollständige Script-/Style-CSP ist bewusst offen. Nonce-basierte CSP einführen; die aktuelle Policy schützt im Wesentlichen nur gegen Framing.
  • Standard-Sitzungen von 30 Tagen Leerlauf/90 Tagen absolut für öffentlich erreichbare Installationen stark verkürzen.
  • HSTS am TLS-Terminator setzen; HTTP konsequent auf HTTPS umleiten.
  • Öffentliche Upload- und Redirect-Routen am Proxy mit Bandbreiten-, Request- und Concurrency-Limits schützen.
  • Sicherheitsereignisse strukturiert protokollieren: Login-Sperren, OIDC-Verknüpfungen, Admin-Erteilung, ungewöhnliche Upload-/Feedback-Raten.
  • Automatisierte Tests für Autorisierungs-Matrix, OIDC-Claim-Typen, Bootstrap-Rennen, Header-Spoofing und Upload-Grenzfälle ergänzen.

Positive Beobachtungen

  • Kein fest eingebettetes Secret oder privater Schlüssel im Repository gefunden.
  • Keine Roh-SQL-Ausführung, Shell-Ausführung oder nutzergesteuertes eval gefunden.
  • Serverseitige Berechtigungsprüfungen sind zentral und werden in den geprüften CRUD-Routen konsistent angewandt.
  • Passwörter verwenden scrypt mit starken Parametern; Sitzungstoken sind zufällig und nur gehasht gespeichert.
  • OIDC prüft Signatur, Issuer, Audience, Nonce, State und PKCE.
  • Uploads werden nach Magic Bytes typisiert, größenbegrenzt, mit bereinigtem Dateinamen und restriktiven Auslieferungsheadern versehen.
  • Fehlerantworten geben unerwartete interne Fehler nicht an Clients weiter.
  • Produktions-Build und ESLint laufen erfolgreich.

Prüfnachweise und Grenzen

  • npm run lint: erfolgreich.
  • npm run build: erfolgreich; der Build führte auch die TypeScript-Prüfung erfolgreich aus.
  • Ein direkter Aufruf von npm run typecheck vor dem Next-Build scheiterte zunächst, weil die von Next generierten globalen LayoutProps-Typen noch fehlten; dies war nach dem Produktions-Build kein Buildfehler.
  • npm audit --omit=dev: drei als „high“ gezählte Paketknoten, eine zugrunde liegende Advisory in deepmerge-ts.
  • Statische Secret-Suche: kein Treffer.
  • Nicht durchgeführt: aktiver Penetrationstest, Laufzeitscan, Container-/Host-Konfigurationsprüfung, IdP-Konfigurationsprüfung, TLS-Scan und Prüfung realer Netzwerkgrenzen. Diese Punkte können das Risiko insbesondere bei S2, S4 und S6 wesentlich verändern.

Priorisierte Maßnahmen

  1. OIDC email_verified fail-closed korrigieren und Tests ergänzen.
  2. AUTH_ENABLED fail-closed machen; öffentliche Bindung/TLS-Proxy absichern.
  3. OIDC-Bootstrap transaktional oder tokengebunden machen.
  4. Lockout- und Rate-Limit-Konzept überarbeiten; Proxy-Vertrauen explizit konfigurieren.
  5. Prisma-Advisory und CSP im nächsten Härtungszyklus beheben.
# Sicherheitsprüfung: qrcode-generator Stand: 24. August 2026 Geprüfter Commit: `4e2d222e8611f01ed11b48bd7b1013cfbf6ced53` Methode: manuelle statische Codeprüfung, Abhängigkeits-Audit, Secret-Suche, Lint, TypeScript- und Produktions-Build-Prüfung. Kein Test gegen eine laufende Produktionsinstanz. ## Kurzurteil Die Anwendung hat eine überdurchschnittlich sorgfältige Sicherheitsbasis: zentrale serverseitige Autorisierung, parametrisierte Datenbankzugriffe über Prisma, starke Passwort-Hashes, gehashte Sitzungstoken, OIDC mit State/Nonce/PKCE, Upload-Signaturprüfung und sandboxartige Header bei der Dateiauslieferung. Im geprüften Stand ist sie trotzdem **nicht bedenkenlos öffentlich bereitzustellen**. Der wichtigste Fehler liegt in der OIDC-Kontoverknüpfung: Ein fehlender `email_verified`-Claim wird als bestätigte E-Mail gewertet. Abhängig vom Identity Provider kann das die Übernahme eines bestehenden lokalen Kontos einschließlich eines Administratorkontos ermöglichen. Hinzu kommen gefährliche Auslieferungsvorgaben (`AUTH_ENABLED=false`), leicht auslösbare Kontosperren, umgehbare In-Memory-Drosselungen und ein Wettlauf beim ersten OIDC-Administrator. ## Befunde ### S1 – Hoch: OIDC verknüpft Konten auch ohne positiv bestätigte E-Mail **Betroffene Stelle:** `src/lib/auth/oidc.ts:326-330`, verwendet in `src/app/api/auth/oidc/callback/route.ts:94-119`. `emailVerified` wird als `payload.email_verified !== false` berechnet. Damit gelten nicht nur `true`, sondern auch ein **fehlender Claim**, `null`, `0` oder eine Zeichenkette als bestätigt. Findet die Callback-Route anschließend ein lokales Konto mit derselben E-Mail-Adresse, hängt sie die fremde OIDC-Identität (`sub`) an dieses Konto. Danach kann sich diese Identität als das lokale Konto anmelden. **Ausnutzbarkeit:** Hoch, wenn der konfigurierte OIDC-Anbieter `email_verified` nicht liefert oder Benutzer ihre E-Mail-Adresse dort unzureichend kontrolliert setzen können. Das ID-Token selbst muss weiterhin gültig signiert sein; dies ist kein Angriff ohne Zugriff auf den IdP. **Auswirkung:** Kontoübernahme, bei passender Adresse auch Instanz-Administratorrechte. **Behebung:** Nur den booleschen Wert `true` akzeptieren: ```ts emailVerified: payload.email_verified === true ``` Noch robuster: Für die automatische Verknüpfung zusätzlich eine explizite Konfigurationsfreigabe verlangen oder lokale und OIDC-Konten nur administrativ verknüpfen. Einen Test für fehlend, `false`, `null`, String und `true` ergänzen. ### S2 – Hoch (Fehlkonfiguration): Authentifizierung ist standardmäßig ausgeschaltet **Betroffene Stellen:** `.env.example:16-22`, `docker-compose.yml:37-40`. Die Compose-Vorgabe startet mit `AUTH_ENABLED=false`. In diesem Modus erzeugt die Anwendung einen `system`-Akteur, der jede Berechtigung besitzt. Gleichzeitig veröffentlicht Compose Port 3000 auf allen Interfaces. Eine versehentlich öffentlich erreichbare Standardinstallation erlaubt damit jedem Besucher Verwaltung, Uploads sowie Anlegen, Ändern und Löschen aller Codes. **Ausnutzbarkeit:** Unmittelbar, sobald der Host aus einem nicht vollständig vertrauenswürdigen Netz erreichbar ist. **Behebung:** Fail-closed ausliefern: `AUTH_ENABLED` in Compose verpflichtend machen (`${AUTH_ENABLED:?…}`) oder standardmäßig `true` setzen. Für bewusst offenen Einzelplatzbetrieb eine deutlich benannte Option verwenden und beim Start eine auffällige Warnung protokollieren. Port standardmäßig an `127.0.0.1` binden oder einen vorgeschalteten TLS-Proxy dokumentiert voraussetzen. ### S3 – Mittel: Jeder kann bekannte Konten gezielt aussperren **Betroffene Stelle:** `src/app/api/auth/route.ts` (`MAX_ATTEMPTS = 8`, 15 Minuten Sperre). Acht falsche Passwörter sperren das betroffene Konto für 15 Minuten. Es gibt keinen Nachweis, dass der Anfragende der Kontoinhaber ist. Ein Angreifer, der die Administratoradresse kennt, kann die Sperre wiederholt erneuern und so die Verwaltung praktisch dauerhaft blockieren. Die zusätzliche IP-Drosselung verhindert dies nicht; acht Versuche liegen unter ihrer Grenze von 20. **Auswirkung:** Gezielter Denial-of-Service gegen einzelne Benutzer, besonders problematisch bei nur einem Administrator. **Behebung:** Progressive Verzögerung statt harter Kontosperre bevorzugen; alternativ Sperren zusätzlich nach vertrauenswürdig ermittelter Quelladresse begrenzen, Admin-Wiederherstellung vorsehen und Ereignisse alarmieren. Niemals allein auf vom Client gelieferte Forwarded-Header vertrauen. ### S4 – Mittel: Drosselungen lassen sich per `X-Forwarded-For` umgehen **Betroffene Stellen:** `src/lib/auth/throttle.ts:56-68`, `src/app/api/feedback/route.ts:61-70`. Die Anwendung übernimmt stets den ersten Wert aus `X-Forwarded-For`. Bei direkter Veröffentlichung (die mitgelieferte Compose-Konfiguration tut genau das) kann jeder Client diesen Header frei wählen. Dadurch lassen sich sowohl die Login-Bremse als auch die öffentliche Feedback-Bremse mit wechselnden Werten umgehen. Die Zähler sind außerdem nur pro Prozess gespeichert und verlieren bei Neustart oder horizontaler Skalierung ihre Wirkung. **Auswirkung:** Erleichtertes Password-Spraying, Feedback-Spam und Datenbankwachstum. Die Kontosperre begrenzt Versuche pro bekanntem Konto, verhindert aber breites Spraying und Feedback-Fluten nicht zuverlässig. **Behebung:** Einen festen Trust-Proxy-Modus einführen: Forwarded-Header nur von bekannten Proxy-Adressen akzeptieren, sonst die Socket-Adresse verwenden. Für mehrere Instanzen einen gemeinsamen, atomaren Zähler (z. B. Redis oder Datenbank) verwenden. Zusätzlich globale Obergrenzen und Body-/Request-Rate-Limits am Reverse Proxy setzen. ### S5 – Mittel: Wettlauf erzeugt mehrere erste OIDC-Administratoren **Betroffene Stelle:** `src/app/api/auth/oidc/callback/route.ts:122-145`. Beim OIDC-Bootstrap werden `user.count() === 0` und `user.create()` getrennt ausgeführt. Zwei gleichzeitig abgeschlossene erste Anmeldungen können beide `istErster=true` sehen und anschließend beide als Instanz-Administrator angelegt werden. Die lokale Passwort-Ersteinrichtung schützt denselben Ablauf bereits korrekt mit einer serialisierbaren Transaktion; der OIDC-Pfad tut dies nicht. **Ausnutzbarkeit:** Nur auf einer frischen Installation und mit einer gültigen IdP-Identität, aber gerade der erste Administrator ist eine besonders empfindliche Vertrauensgrenze. **Behebung:** Prüfung und Anlage wie im lokalen Setup in eine serialisierbare Transaktion legen und Serialisierungsfehler sicher wiederholen. Noch besser: Bootstrap durch ein einmaliges, serverseitiges Setup-Token oder eine vorab erlaubte Administratoridentität absichern. ### S6 – Niedrig bis mittel: CSRF-/Proxy-Vertrauensmodell ist fragil **Betroffene Stellen:** `src/lib/http.ts:18-30`, `src/lib/auth/session.ts:60-65`, `src/lib/auth/oidc.ts:106-121`. Die Origin-Prüfung vergleicht nur `origin.host`, nicht das vollständige Origin-Tupel aus Schema, Host und Port, und bevorzugt ungeprüft `X-Forwarded-Host`. Auch das `Secure`-Flag der Sitzung vertraut `X-Forwarded-Proto`. Bei einem korrekt konfigurierten Reverse Proxy ist das meist ausreichend; bei direkter Exposition oder einem Proxy, der eingehende Forwarded-Header nicht überschreibt, entscheidet jedoch der Client über sicherheitsrelevante Werte. Ein fehlender `Origin`-Header wird pauschal akzeptiert. Für klassische Browser-CSRF-Angriffe ist das oft vertretbar, lässt aber keinen Schutz gegen Clients zu, die den Header entfernen, und erschwert ein eindeutiges Sicherheitsversprechen. **Behebung:** Explizite Liste vertrauenswürdiger öffentlicher Origins und Proxy-Hops konfigurieren. Für schreibende Cookie-authentifizierte Requests vollständigen Origin-Vergleich oder ein CSRF-Token verlangen. Forwarded-Header nur hinter einem bekannten Proxy auswerten. `Secure` primär aus einer verpflichtenden HTTPS-`BASE_URL` ableiten. ### S7 – Niedrig: Bekannte High-Advisory in der Prisma-Toolchain `npm audit --omit=dev` meldet `GHSA-ggr8-5vv4-36mx` in `deepmerge-ts@7.1.5`, transitiv über `@prisma/config@7.9.1`/`prisma@7.9.1`. Die Schwachstelle ist Stack-Erschöpfung beim Zusammenführen rekursiver Objektgraphen. Die praktische Remote-Ausnutzbarkeit ist hier niedrig, weil Prisma-Konfiguration nicht aus HTTP-Eingaben erzeugt wird. Die Prisma-CLI wird jedoch in das Laufzeit-Image kopiert und beim Containerstart für Migrationen verwendet; daher sollte der Befund nicht einfach als reine Entwicklungsabhängigkeit ignoriert werden. **Behebung:** Auf eine Prisma-Version aktualisieren, die `deepmerge-ts >= 8` verwendet, sobald kompatibel verfügbar, und den Lockfile-Audit in CI erzwingen. Kein blindes `npm audit fix --force` auf Prisma 6 durchführen. ## Härtungsempfehlungen - Die vollständige Script-/Style-CSP ist bewusst offen. Nonce-basierte CSP einführen; die aktuelle Policy schützt im Wesentlichen nur gegen Framing. - Standard-Sitzungen von 30 Tagen Leerlauf/90 Tagen absolut für öffentlich erreichbare Installationen stark verkürzen. - HSTS am TLS-Terminator setzen; HTTP konsequent auf HTTPS umleiten. - Öffentliche Upload- und Redirect-Routen am Proxy mit Bandbreiten-, Request- und Concurrency-Limits schützen. - Sicherheitsereignisse strukturiert protokollieren: Login-Sperren, OIDC-Verknüpfungen, Admin-Erteilung, ungewöhnliche Upload-/Feedback-Raten. - Automatisierte Tests für Autorisierungs-Matrix, OIDC-Claim-Typen, Bootstrap-Rennen, Header-Spoofing und Upload-Grenzfälle ergänzen. ## Positive Beobachtungen - Kein fest eingebettetes Secret oder privater Schlüssel im Repository gefunden. - Keine Roh-SQL-Ausführung, Shell-Ausführung oder nutzergesteuertes `eval` gefunden. - Serverseitige Berechtigungsprüfungen sind zentral und werden in den geprüften CRUD-Routen konsistent angewandt. - Passwörter verwenden scrypt mit starken Parametern; Sitzungstoken sind zufällig und nur gehasht gespeichert. - OIDC prüft Signatur, Issuer, Audience, Nonce, State und PKCE. - Uploads werden nach Magic Bytes typisiert, größenbegrenzt, mit bereinigtem Dateinamen und restriktiven Auslieferungsheadern versehen. - Fehlerantworten geben unerwartete interne Fehler nicht an Clients weiter. - Produktions-Build und ESLint laufen erfolgreich. ## Prüfnachweise und Grenzen - `npm run lint`: erfolgreich. - `npm run build`: erfolgreich; der Build führte auch die TypeScript-Prüfung erfolgreich aus. - Ein direkter Aufruf von `npm run typecheck` vor dem Next-Build scheiterte zunächst, weil die von Next generierten globalen `LayoutProps`-Typen noch fehlten; dies war nach dem Produktions-Build kein Buildfehler. - `npm audit --omit=dev`: drei als „high“ gezählte Paketknoten, eine zugrunde liegende Advisory in `deepmerge-ts`. - Statische Secret-Suche: kein Treffer. - Nicht durchgeführt: aktiver Penetrationstest, Laufzeitscan, Container-/Host-Konfigurationsprüfung, IdP-Konfigurationsprüfung, TLS-Scan und Prüfung realer Netzwerkgrenzen. Diese Punkte können das Risiko insbesondere bei S2, S4 und S6 wesentlich verändern. ## Priorisierte Maßnahmen 1. OIDC `email_verified` fail-closed korrigieren und Tests ergänzen. 2. `AUTH_ENABLED` fail-closed machen; öffentliche Bindung/TLS-Proxy absichern. 3. OIDC-Bootstrap transaktional oder tokengebunden machen. 4. Lockout- und Rate-Limit-Konzept überarbeiten; Proxy-Vertrauen explizit konfigurieren. 5. Prisma-Advisory und CSP im nächsten Härtungszyklus beheben.
florian.wilde added the in-arbeit label 2026-08-23 22:43:21 +00:00
florian.wilde started working 2026-08-23 22:43:41 +00:00
Author
Owner

🤖 Claude Code hat mit der Umsetzung begonnen.

  • Branch: fix/20-sicherheitspruefung
  • Verstanden als: Die sieben Befunde der Prüfung abarbeiten — zuerst die, die eine echte Lücke beschreiben, und dabei jeden Punkt vorher am Code nachprüfen statt ihn zu übernehmen.

Nachgeprüft: alle sieben treffen zu. Besonders S1 — der Kommentar im Code sagt ausdrücklich „Verknüpfen nur bei bestätigter Adresse“, und die Berechnung payload.email_verified !== false hebelt genau das aus. Ein fehlender Claim gilt damit als bestätigt.

  • Geplantes Vorgehen:
    • S1, S5 — klare Fehler, werden behoben (strikt === true; Bootstrap in eine serialisierbare Transaktion wie bei der lokalen Ersteinrichtung).
    • S2 — AUTH_ENABLED wird fail-closed: Vorgabe true, und wer sie abschaltet, bekommt beim Start eine deutliche Warnung ins Protokoll.
    • S6 — die beiden Stellen, an denen der Client über Sicherheitsentscheidungen bestimmt: Secure künftig aus dem Schema von BASE_URL statt aus X-Forwarded-Proto; die Herkunftsprüfung gegen eine serverseitige Liste (BASE_URL + registrierte Domains) statt gegen den mitgeschickten Host-Header.
    • S3 — die Kontosperre soll den Besitzer nicht mehr aussperren können: Bei richtigem Passwort wird auch während der Sperre angemeldet. Ein Angreifer ohne Passwort kann damit niemanden mehr blockieren, die Bremse gegen Durchprobieren bleibt.
    • S4, S7 — bleiben offen und werden begründet dokumentiert. Beide brauchen eine Entscheidung, die über diesen Zweig hinausgeht (Proxy-Vertrauensmodell mit gemeinsamem Zähler; Prisma-Aktualisierung, für die es noch keine Fassung ohne die Advisory gibt — 7.9.1 ist die neueste und hängt weiter an deepmerge-ts@7.1.5).

Zeiterfassung läuft.

🤖 **Claude Code hat mit der Umsetzung begonnen.** - Branch: `fix/20-sicherheitspruefung` - Verstanden als: Die sieben Befunde der Prüfung abarbeiten — zuerst die, die eine echte Lücke beschreiben, und dabei jeden Punkt vorher am Code nachprüfen statt ihn zu übernehmen. **Nachgeprüft: alle sieben treffen zu.** Besonders S1 — der Kommentar im Code sagt ausdrücklich „Verknüpfen nur bei bestätigter Adresse“, und die Berechnung `payload.email_verified !== false` hebelt genau das aus. Ein fehlender Claim gilt damit als bestätigt. - Geplantes Vorgehen: - **S1, S5** — klare Fehler, werden behoben (strikt `=== true`; Bootstrap in eine serialisierbare Transaktion wie bei der lokalen Ersteinrichtung). - **S2** — `AUTH_ENABLED` wird fail-closed: Vorgabe `true`, und wer sie abschaltet, bekommt beim Start eine deutliche Warnung ins Protokoll. - **S6** — die beiden Stellen, an denen der Client über Sicherheitsentscheidungen bestimmt: `Secure` künftig aus dem Schema von `BASE_URL` statt aus `X-Forwarded-Proto`; die Herkunftsprüfung gegen eine serverseitige Liste (BASE_URL + registrierte Domains) statt gegen den mitgeschickten Host-Header. - **S3** — die Kontosperre soll den Besitzer nicht mehr aussperren können: Bei **richtigem** Passwort wird auch während der Sperre angemeldet. Ein Angreifer ohne Passwort kann damit niemanden mehr blockieren, die Bremse gegen Durchprobieren bleibt. - **S4, S7** — bleiben offen und werden begründet dokumentiert. Beide brauchen eine Entscheidung, die über diesen Zweig hinausgeht (Proxy-Vertrauensmodell mit gemeinsamem Zähler; Prisma-Aktualisierung, für die es noch keine Fassung ohne die Advisory gibt — 7.9.1 ist die neueste und hängt weiter an `deepmerge-ts@7.1.5`). Zeiterfassung läuft.
florian.wilde worked for 18 minutes 2026-08-23 23:02:13 +00:00
florian.wilde added zu-testen and removed in-arbeit labels 2026-08-23 23:03:03 +00:00
Author
Owner

✅ Umsetzung abgeschlossen — bereit zum Testen.

Alle sieben Befunde treffen zu. Vier behoben, drei begründet offen.

Befund Stand
S1 OIDC wertet unbestätigte E-Mail als bestätigt behoben
S2 Anmeldung standardmäßig aus behoben
S3 Kontosperre erlaubt gezieltes Aussperren offen, begründet
S4 Bremsen über X-Forwarded-For umgehbar offen, begründet
S5 Wettlauf beim ersten OIDC-Administrator behoben
S6 Herkunftsprüfung ohne Schema behoben
S7 Advisory in der Prisma-Toolchain offen, keine Fassung verfügbar

Was geändert wurde

  • S1: payload.email_verified === true statt !== false. Der Kommentar daneben beschrieb die Absicht schon richtig — die Zeile darunter tat das Gegenteil.
  • S2: Der Fehler saß tiefer als gemeldet. Nicht nur die Compose-Vorgabe: isAuthEnabled() verlangte den Wert "true", alles andere hieß „aus“. Eine vergessene oder falsch geschriebene Variable ergab eine Anwendung ohne jede Anmeldung. Jetzt umgekehrt, plus Vorgaben auf true und eine mehrzeilige Startwarnung im Container.
  • S5: Zählen und Anlegen in einer serialisierbaren Transaktion, wie die lokale Ersteinrichtung es längst tat.
  • S6: Das Schema wird mitverglichen und stammt aus BASE_URL.

Abweichung von meinem Plan oben: S3 wollte ich beheben, indem während der Sperre weiter geprüft und ein richtiges Passwort durchgelassen wird. Beim Nachrechnen verworfen: Eine Prüfung kostet hier rund 128 MiB (scrypt mit N = 2¹⁷). Wer sie beliebig oft auslösen darf, legt den Server lahm — aus einer Sperre gegen ein Konto würde eine gegen alle. Der Punkt braucht einen eigenen Entwurf, zusammen mit S4.

Geänderte Dateien

  • src/lib/auth/oidc.ts, src/app/api/auth/oidc/callback/route.ts
  • src/lib/auth/actor.ts, src/lib/http.ts
  • docker-compose.yml, .env.example, docker/entrypoint.sh
  • docs/sicherheit.md — vier neue behobene Punkte, drei offene mit Begründung

So testest du es

  1. git switch fix/20-sicherheitspruefung
  2. Wichtig für deine Installation: In deiner .env steht AUTH_ENABLED=false. Das bleibt wirksam — an deinem Stack ändert sich nichts außer der Warnung im Protokoll.
  3. docker compose up -d --build app, dann docker compose logs app — die Warnung „ACHTUNG: AUTH_ENABLED=false“ muss dastehen.
  4. Gegenprobe: Zeile in der .env auskommentieren und neu starten. Erwartet: Die Anwendung verlangt jetzt eine Anmeldung, obwohl gar nichts gesetzt ist.
  5. Normale Bedienung durchklicken — Code anlegen, ändern, löschen. Die geänderte Herkunftsprüfung darf nichts blockieren.

Geprüft: Eigene Reihe zu den Befunden 34 von 34, darunter die Wahrheitstabellen für email_verified und AUTH_ENABLED. Am laufenden Server nachgestellt: mit leerem AUTH_ENABLED antwortet / mit 307 auf /anmelden, /api/codes mit 401. Bestehende Reihen: sicherheit 21/21 (frische Datenbank, Anmeldung an), dubletten 24/24, filter-art 28/28, domain-check 38/38, logo 44/44.

Aufgewendete Zeit: 00:18
Pull Request: #21

Nach Freigabe: /issue-freigabe 20


Am Rande aufgefallen (kein eigenes Issue angelegt):

  • S3 und S4 gehören zusammen in einen Entwurf „Bremsen und Sperren“: ansteigende Verzögerung ohne Speicherlast, ausdrückliches Proxy-Vertrauen, gemeinsamer Zähler bei mehreren Instanzen.
  • Der Prisma-Punkt braucht eine Erinnerung, keine Arbeit — er löst sich mit der nächsten passenden Fassung.
  • Die Prüfung empfiehlt außerdem eine nonce-basierte CSP. Das ist eine eigene, spürbare Umbauarbeit durch die ganze Anwendung und steht als Härtungspunkt schon im Bericht.
✅ **Umsetzung abgeschlossen — bereit zum Testen.** <!-- claude-status branch: fix/20-sicherheitspruefung pr: 21 zeit_sekunden: 1112 --> **Alle sieben Befunde treffen zu.** Vier behoben, drei begründet offen. | | Befund | Stand | | --- | --- | --- | | S1 | OIDC wertet unbestätigte E-Mail als bestätigt | **behoben** | | S2 | Anmeldung standardmäßig aus | **behoben** | | S3 | Kontosperre erlaubt gezieltes Aussperren | offen, begründet | | S4 | Bremsen über `X-Forwarded-For` umgehbar | offen, begründet | | S5 | Wettlauf beim ersten OIDC-Administrator | **behoben** | | S6 | Herkunftsprüfung ohne Schema | **behoben** | | S7 | Advisory in der Prisma-Toolchain | offen, keine Fassung verfügbar | **Was geändert wurde** - **S1:** `payload.email_verified === true` statt `!== false`. Der Kommentar daneben beschrieb die Absicht schon richtig — die Zeile darunter tat das Gegenteil. - **S2:** Der Fehler saß tiefer als gemeldet. Nicht nur die Compose-Vorgabe: `isAuthEnabled()` verlangte den Wert `"true"`, alles andere hieß „aus“. Eine **vergessene oder falsch geschriebene** Variable ergab eine Anwendung ohne jede Anmeldung. Jetzt umgekehrt, plus Vorgaben auf `true` und eine mehrzeilige Startwarnung im Container. - **S5:** Zählen und Anlegen in einer serialisierbaren Transaktion, wie die lokale Ersteinrichtung es längst tat. - **S6:** Das Schema wird mitverglichen und stammt aus `BASE_URL`. **Abweichung von meinem Plan oben:** S3 wollte ich beheben, indem während der Sperre weiter geprüft und ein richtiges Passwort durchgelassen wird. Beim Nachrechnen verworfen: Eine Prüfung kostet hier rund **128 MiB** (scrypt mit N = 2¹⁷). Wer sie beliebig oft auslösen darf, legt den Server lahm — aus einer Sperre gegen ein Konto würde eine gegen alle. Der Punkt braucht einen eigenen Entwurf, zusammen mit S4. **Geänderte Dateien** - `src/lib/auth/oidc.ts`, `src/app/api/auth/oidc/callback/route.ts` - `src/lib/auth/actor.ts`, `src/lib/http.ts` - `docker-compose.yml`, `.env.example`, `docker/entrypoint.sh` - `docs/sicherheit.md` — vier neue behobene Punkte, drei offene mit Begründung **So testest du es** 1. `git switch fix/20-sicherheitspruefung` 2. **Wichtig für deine Installation:** In deiner `.env` steht `AUTH_ENABLED=false`. Das bleibt wirksam — an deinem Stack ändert sich nichts außer der Warnung im Protokoll. 3. `docker compose up -d --build app`, dann `docker compose logs app` — die Warnung „ACHTUNG: AUTH_ENABLED=false“ muss dastehen. 4. Gegenprobe: Zeile in der `.env` auskommentieren und neu starten. Erwartet: Die Anwendung verlangt jetzt eine Anmeldung, obwohl gar nichts gesetzt ist. 5. Normale Bedienung durchklicken — Code anlegen, ändern, löschen. Die geänderte Herkunftsprüfung darf nichts blockieren. **Geprüft:** Eigene Reihe zu den Befunden **34 von 34**, darunter die Wahrheitstabellen für `email_verified` und `AUTH_ENABLED`. Am laufenden Server nachgestellt: mit leerem `AUTH_ENABLED` antwortet `/` mit 307 auf `/anmelden`, `/api/codes` mit 401. Bestehende Reihen: `sicherheit` 21/21 (frische Datenbank, Anmeldung an), `dubletten` 24/24, `filter-art` 28/28, `domain-check` 38/38, `logo` 44/44. **Aufgewendete Zeit:** 00:18 **Pull Request:** #21 Nach Freigabe: `/issue-freigabe 20` --- **Am Rande aufgefallen** (kein eigenes Issue angelegt): - S3 und S4 gehören zusammen in einen Entwurf „Bremsen und Sperren“: ansteigende Verzögerung ohne Speicherlast, ausdrückliches Proxy-Vertrauen, gemeinsamer Zähler bei mehreren Instanzen. - Der Prisma-Punkt braucht eine Erinnerung, keine Arbeit — er löst sich mit der nächsten passenden Fassung. - Die Prüfung empfiehlt außerdem eine nonce-basierte CSP. Das ist eine eigene, spürbare Umbauarbeit durch die ganze Anwendung und steht als Härtungspunkt schon im Bericht.
florian.wilde added in-arbeit and removed zu-testen labels 2026-08-23 23:14:42 +00:00
florian.wilde started working 2026-08-23 23:14:48 +00:00
florian.wilde worked for 44 minutes 2026-08-23 23:59:40 +00:00
florian.wilde added zu-testen and removed in-arbeit labels 2026-08-24 00:00:12 +00:00
Author
Owner

✅ Nachgelegt: die offenen Punkte sind zu.

Nach „mach bitte alles sicher“ sind jetzt sechs der sieben Befunde behoben und die Härtungsliste weitgehend abgearbeitet.

Befund Stand
S1 OIDC wertet unbestätigte E-Mail als bestätigt behoben
S2 Anmeldung standardmäßig aus behoben
S3 Kontosperre erlaubt gezieltes Aussperren behoben
S4 Bremsen über X-Forwarded-For umgehbar behoben
S5 Wettlauf beim ersten OIDC-Administrator behoben
S6 Herkunftsprüfung ohne Schema behoben
S7 Advisory in der Prisma-Toolchain offen — keine Fassung verfügbar
Härtung Nonce-basierte CSP umgesetzt
Härtung Sicherheitsereignisse protokollieren umgesetzt

S3 — aus der Sperre wird eine Wartezeit. Meine frühere Absage bezog sich auf einen anderen Weg (während der Sperre weiter prüfen). Der richtige Weg braucht gar keine Prüfung: Die ersten vier Fehlversuche bleiben folgenlos, danach verdoppelt sich die Wartezeit bis zu einer Minute.

Fehlversuche Wartezeit
bis 4 keine
5 1 s
7 4 s
10 32 s
ab 11 60 s

Der Besitzer kommt spätestens nach einer Minute hinein statt nach einer Viertelstunde gar nicht. Ausgewertet wird die Wartezeit vor der Passwortprüfung — ein ohnehin abgewiesener Versuch kostet keine 128 MiB.

S4 — drei Stufen statt einer.

  1. Je Absender: liest X-Forwarded-For nur noch mit TRUST_PROXY=true. Ohne Proxy wählt den Wert jeder Aufrufer selbst; eine so umgehbare Bremse ist eine Behauptung, dann lieber ehrlich keine.
  2. Je Konto: die Wartezeit oben. Hängt an der Datenbank, nicht an einer Kopfzeile.
  3. Für die Installation: 60 Passwortprüfungen und 120 Rückmeldungen je Minute. Die einzige Stufe, die sich nicht über Kopfzeilen umgehen lässt — und die, die den Speicher schützt.

CSP mit Nonce. Vollständige Policy statt nur frame-ancestors: strict-dynamic, frischer Nonce je Anfrage, default-src 'self', object-src 'none', base-uri/form-action auf 'self'. Ein eingeschleustes Skript hat keinen Nonce und läuft nicht.

Zwei Lockerungen sind bewusst und stehen begründet in der Doku: style-src erlaubt weiter 'unsafe-inline' (ein Nonce deckt keine style="…"-Attribute, und über eines lässt sich kein Code ausführen), und media-src erlaubt https: (der Typ „Video“ nimmt ausdrücklich Direktlinks an — das hat mir der Test auch prompt um die Ohren gehauen).

Protokoll. src/lib/auth/protokoll.ts schreibt je Ereignis eine JSON-Zeile: Fehlversuche mit Zahl und Wartezeit, abgelehnte und erfolgte OIDC-Verknüpfungen, jede Vergabe von Administratorrechten. Ohne Passwörter, Token und Adressen — Konten stehen mit ihrer Id da.

Neue Einstellung: TRUST_PROXY (Vorgabe false) in .env.example, docker-compose.yml und README.

Geänderte Dateien (zusätzlich zum ersten Durchgang)

  • src/lib/auth/throttle.ts — die drei Stufen
  • src/lib/auth/protokoll.ts (neu)
  • src/app/api/auth/route.ts, src/app/api/feedback/route.ts, src/app/api/auth/oidc/callback/route.ts
  • src/proxy.ts, src/app/layout.tsx — CSP und Nonce
  • .env.example, docker-compose.yml, README.md, docs/sicherheit.md

So testest du es

  1. git switch fix/20-sicherheitspruefung
  2. docker compose up -d --build app
  3. docker compose logs app — die Warnung zu AUTH_ENABLED=false steht da.
  4. Normal durchklicken: Codes anlegen, Landingpage öffnen, Video abspielen, Verwaltung. Wenn die CSP etwas blockiert, bleibt die Seite leer oder ein Knopf reagiert nicht — genau darauf achten.
  5. Mit eingeschalteter Anmeldung: fünfmal falsch anmelden, dann richtig. Erwartet: eine Meldung in Sekunden, und nach kurzem Warten kommst du hinein.

Geprüft

  • Neue Reihe zum neuen Verhalten: 45 von 45 — darunter live nachgestellt, dass fünf Fehlversuche in eine Wartezeit von einer Sekunde münden und der Besitzer danach hineinkommt.
  • Reihe zu den Befunden: 35 von 35.
  • 19 bestehende Reihen gegen den fertig gebauten Container, alle grün: e2e 79, browser 39, browser-types 25, filter-art 28, dubletten 24, logo 44, domain-check 38, hilfe-domains 24, typen-gruppen 38, landing 31, landing-social-video 31, codes-view 33, darkmode 38, kurzlinks 57, statisch 38, uploads 48, branding 42, version 20 — dazu auth 63, codes-groups 9, slug-rechte 29 und sicherheit 21 gegen eine frische Instanz mit Anmeldung.

Aufgewendete Zeit: 01:03 (beide Durchgänge)
Pull Request: #21

Nach Freigabe: /issue-freigabe 20

✅ **Nachgelegt: die offenen Punkte sind zu.** <!-- claude-status branch: fix/20-sicherheitspruefung pr: 21 zeit_sekunden: 3804 --> Nach „mach bitte alles sicher“ sind jetzt **sechs der sieben Befunde behoben** und die Härtungsliste weitgehend abgearbeitet. | | Befund | Stand | | --- | --- | --- | | S1 | OIDC wertet unbestätigte E-Mail als bestätigt | **behoben** | | S2 | Anmeldung standardmäßig aus | **behoben** | | S3 | Kontosperre erlaubt gezieltes Aussperren | **behoben** | | S4 | Bremsen über `X-Forwarded-For` umgehbar | **behoben** | | S5 | Wettlauf beim ersten OIDC-Administrator | **behoben** | | S6 | Herkunftsprüfung ohne Schema | **behoben** | | S7 | Advisory in der Prisma-Toolchain | offen — keine Fassung verfügbar | | Härtung | Nonce-basierte CSP | **umgesetzt** | | Härtung | Sicherheitsereignisse protokollieren | **umgesetzt** | **S3 — aus der Sperre wird eine Wartezeit.** Meine frühere Absage bezog sich auf einen anderen Weg (während der Sperre weiter prüfen). Der richtige Weg braucht gar keine Prüfung: Die ersten vier Fehlversuche bleiben folgenlos, danach verdoppelt sich die Wartezeit bis zu **einer Minute**. | Fehlversuche | Wartezeit | | --- | --- | | bis 4 | keine | | 5 | 1 s | | 7 | 4 s | | 10 | 32 s | | ab 11 | 60 s | Der Besitzer kommt spätestens nach einer Minute hinein statt nach einer Viertelstunde gar nicht. Ausgewertet wird die Wartezeit **vor** der Passwortprüfung — ein ohnehin abgewiesener Versuch kostet keine 128 MiB. **S4 — drei Stufen statt einer.** 1. **Je Absender:** liest `X-Forwarded-For` nur noch mit `TRUST_PROXY=true`. Ohne Proxy wählt den Wert jeder Aufrufer selbst; eine so umgehbare Bremse ist eine Behauptung, dann lieber ehrlich keine. 2. **Je Konto:** die Wartezeit oben. Hängt an der Datenbank, nicht an einer Kopfzeile. 3. **Für die Installation:** 60 Passwortprüfungen und 120 Rückmeldungen je Minute. Die einzige Stufe, die sich **nicht** über Kopfzeilen umgehen lässt — und die, die den Speicher schützt. **CSP mit Nonce.** Vollständige Policy statt nur `frame-ancestors`: `strict-dynamic`, frischer Nonce je Anfrage, `default-src 'self'`, `object-src 'none'`, `base-uri`/`form-action` auf `'self'`. Ein eingeschleustes Skript hat keinen Nonce und läuft nicht. Zwei Lockerungen sind bewusst und stehen begründet in der Doku: `style-src` erlaubt weiter `'unsafe-inline'` (ein Nonce deckt keine `style="…"`-Attribute, und über eines lässt sich kein Code ausführen), und `media-src` erlaubt `https:` (der Typ „Video“ nimmt ausdrücklich Direktlinks an — das hat mir der Test auch prompt um die Ohren gehauen). **Protokoll.** `src/lib/auth/protokoll.ts` schreibt je Ereignis eine JSON-Zeile: Fehlversuche mit Zahl und Wartezeit, abgelehnte und erfolgte OIDC-Verknüpfungen, jede Vergabe von Administratorrechten. Ohne Passwörter, Token und Adressen — Konten stehen mit ihrer Id da. **Neue Einstellung:** `TRUST_PROXY` (Vorgabe `false`) in `.env.example`, `docker-compose.yml` und README. **Geänderte Dateien** (zusätzlich zum ersten Durchgang) - `src/lib/auth/throttle.ts` — die drei Stufen - `src/lib/auth/protokoll.ts` (neu) - `src/app/api/auth/route.ts`, `src/app/api/feedback/route.ts`, `src/app/api/auth/oidc/callback/route.ts` - `src/proxy.ts`, `src/app/layout.tsx` — CSP und Nonce - `.env.example`, `docker-compose.yml`, `README.md`, `docs/sicherheit.md` **So testest du es** 1. `git switch fix/20-sicherheitspruefung` 2. `docker compose up -d --build app` 3. `docker compose logs app` — die Warnung zu `AUTH_ENABLED=false` steht da. 4. Normal durchklicken: Codes anlegen, Landingpage öffnen, Video abspielen, Verwaltung. **Wenn die CSP etwas blockiert, bleibt die Seite leer oder ein Knopf reagiert nicht** — genau darauf achten. 5. Mit eingeschalteter Anmeldung: fünfmal falsch anmelden, dann richtig. Erwartet: eine Meldung in **Sekunden**, und nach kurzem Warten kommst du hinein. **Geprüft** - Neue Reihe zum neuen Verhalten: **45 von 45** — darunter live nachgestellt, dass fünf Fehlversuche in eine Wartezeit von einer Sekunde münden und der Besitzer danach hineinkommt. - Reihe zu den Befunden: **35 von 35**. - **19 bestehende Reihen gegen den fertig gebauten Container**, alle grün: e2e 79, browser 39, browser-types 25, filter-art 28, dubletten 24, logo 44, domain-check 38, hilfe-domains 24, typen-gruppen 38, landing 31, landing-social-video 31, codes-view 33, darkmode 38, kurzlinks 57, statisch 38, uploads 48, branding 42, version 20 — dazu auth 63, codes-groups 9, slug-rechte 29 und sicherheit 21 gegen eine frische Instanz mit Anmeldung. **Aufgewendete Zeit:** 01:03 (beide Durchgänge) **Pull Request:** #21 Nach Freigabe: `/issue-freigabe 20`
Author
Owner

🚀 Freigegeben und nach main übernommen.

  • Merge-Commit: 6743dc0
  • Pull Request: #21 (gemergt)
  • Gesamtaufwand: 01:03

Sechs der sieben Befunde behoben, dazu die nonce-basierte CSP und das Protokoll für Sicherheitsereignisse. Offen bleibt allein S7 — für die Prisma-Advisory gibt es noch keine Fassung ohne deepmerge-ts@7.1.5.

Typprüfung und Linter auf main nach dem Merge: grün.

Issue wird geschlossen.

🚀 **Freigegeben und nach `main` übernommen.** <!-- claude-status merge: 6743dc0 pr: 21 zeit_sekunden: 3804 --> - Merge-Commit: `6743dc0` - Pull Request: #21 (gemergt) - Gesamtaufwand: 01:03 Sechs der sieben Befunde behoben, dazu die nonce-basierte CSP und das Protokoll für Sicherheitsereignisse. Offen bleibt allein S7 — für die Prisma-Advisory gibt es noch keine Fassung ohne `deepmerge-ts@7.1.5`. Typprüfung und Linter auf `main` nach dem Merge: grün. Issue wird geschlossen.
florian.wilde removed the zu-testen label 2026-08-24 07:42:13 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Total Time Spent: 1 hour 3 minutes
florian.wilde
1 hour 3 minutes
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: florian.wilde/qrcode-generator#20