Project-Image-Uploader/FeatureRequests/FEATURE_REQUEST-security.md

20 KiB
Raw Blame History

FEATURE_REQUEST: Security — Server-seitige Sessions für Admin-API

Umsetzungsaufgaben (konkret & eindeutig für KI / Entwickler)

Die folgenden Aufgaben sind Schritt-für-Schritt auszuführen. Jede Aufgabe enthält das gewünschte Ergebnis und minimalen Beispielcode oder Befehle. Die KI/Entwickler sollen die Änderungen als Code-Patches anlegen, Tests hinzufügen und die Dokumentation aktualisieren.

  1. Session-Store & Session-Konfiguration

    • Ziel: Server-seitige Sessions für Admin-Login verfügbar machen.
    • Schritte:
      • Installiere Packages: npm install express-session connect-sqlite3 --save (Backend).
      • In backend/src/server.js (oder Entrypoint) konfiguriere express-session mit connect-sqlite3:
        const session = require('express-session');
        const SQLiteStore = require('connect-sqlite3')(session);
        app.use(session({
          store: new SQLiteStore({ db: 'sessions.sqlite' }),
          secret: process.env.ADMIN_SESSION_SECRET,
          resave: false,
          saveUninitialized: false,
          cookie: { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'Strict', maxAge: 8*60*60*1000 }
        }));
        
    • Abnahme: Session-Cookie (sid) wird gesetzt nach Login, cookie-Flags korrekt.
  2. Login-Endpoint (Admin)

    • Ziel: Admin kann sich mit Benutzername/Passwort anmelden; Backend erstellt Session.
    • Schritte:
      • Füge POST /auth/login hinzu, prüft Credentials (z. B. gegen environment-stored admin user/pass oder htpasswd), legt req.session.user = { role: 'admin' } an und req.session.csrfToken = randomHex() an.
      • Rückgabe: 200 OK. Cookie wird automatisch gesetzt (credentials: 'include' vom Frontend).
    • Abnahme: Nach POST /auth/login existiert req.session.user und req.session.csrfToken.
  3. CSRF-Endpoint + Middleware

    • Ziel: Session-gebundenen CSRF-Token ausgeben und Requests schützen.
    • Schritte:
      • Endpoint GET /auth/csrf-token gibt { csrfToken: req.session.csrfToken } zurück (nur wenn eingeloggt).
      • Middleware requireCsrf prüft req.headers['x-csrf-token'] === req.session.csrfToken für state-changing Methoden.
    • Abnahme: state-changing Admin-Requests ohne oder mit falschem X-CSRF-Token bekommen 403.
  4. Backend-Auth-Middleware für Admin-API

    • Ziel: Alle /api/admin/* Endpoints prüfen Session statt Client-Token.
    • Schritte:
      • Ersetze oder erweitere bestehende Admin-Auth-Middleware (middlewares/auth.js) so, dass sie req.session.user && req.session.user.role === 'admin' prüft; falls nicht gesetzt → 403.
    • Abnahme: GET /api/admin/* ohne Session → 403; mit gültiger Session → durchgelassen.
  5. Frontend-Änderungen (adminApi)

    • Ziel: Frontend sendet keine Admin-Bearer-Tokens mehr; verwendet Cookie-Session + CSRF-Header.
    • Schritte:
      • Entferne in frontend/src/services/adminApi.js die Abhängigkeit von process.env.REACT_APP_ADMIN_API_KEY.
      • Passe adminFetch/adminRequest an: bei Requests setze credentials: 'include' und füge X-CSRF-Token Header (Token bezieht Frontend über GET /auth/csrf-token nach Login).
      • Dokumentiere in frontend/README oder Code-Kommentar, dass Admin-UI nach Login fetch('/auth/csrf-token', { credentials: 'include' }) aufruft.
    • Abnahme: adminApi.js sendet keine Bearer-Header; admin Requests beinhalten credentials: 'include' und X-CSRF-Token.
  6. Entfernen von Admin-Key aus Frontend Build/Compose/Dockerfile

    • Ziel: Keine Weitergabe von ADMIN_API_KEY an frontend und kein Kopieren sensibler .env in Frontend-Image.
    • Schritte:
      • Entferne Zeile - REACT_APP_ADMIN_API_KEY=${ADMIN_API_KEY} aus docker/prod/docker-compose.yml.
      • Entferne COPY docker/prod/frontend/config/.env ./.env aus docker/prod/frontend/Dockerfile oder stelle sicher, dass diese Datei ausschließlich non-sensitive Keys enthält.
      • Dokumentiere in FeatureRequests/FEATURE_REQUEST-security.md welche Keys im runtime-env.sh erlaubt sind (z. B. API_URL, APP_VERSION).
    • Abnahme: docker-compose enthält keine Übergabe an frontend; Build und Image enthalten keine Production-Secrets.
  7. Secrets-Handling / Deployment

    • Ziel: Secrets nur in Backend-Umgebung bereitstellen.
    • Schritte:
      • Setze ADMIN_API_KEY und ADMIN_SESSION_SECRET in CI/CD Secrets oder Docker Secrets und referenziere sie nur im backend Service.
      • Beispiel-Dokumentation für CI: wie man Secret in GitLab/GitHub Actions setzt und an Container übergibt.
    • Abnahme: Secrets sind nicht in Repo/Images; docker inspect der frontend-Container zeigt keinen Admin-Key.
  8. Tests & CI-Checks

    • Ziel: Automatisierte Verifikation der Sicherheitsregeln.
    • Schritte:
      • Integrationstest 1: GET /api/admin/some ohne Session → expect 403.
      • Integrationstest 2: POST /auth/login with admin credentials → expect Set-Cookie; then GET /auth/csrf-token → receive token; then POST /api/admin/action with X-CSRF-Token → expect 200.
      • Build-scan-Check: CI Schritt rg REACT_APP_ADMIN_API_KEY build/ || true fails if found.
    • Abnahme: Tests grün; CI verweigert Merge wenn Build enthält Admin-Key.
  9. Key-Leak Reaktion (konkrete Anweisungen)

    • Ziel: Falls ein Admin-Key geleakt wurde, sichere, koordinierte Rotation.
    • Schritte:
      • Scannen: trufflehog --regex --entropy=True . oder git-secrets scan.
      • Entfernen: git-filter-repo --replace-text passwords.txt oder bfg --replace-text passwords.txt (siehe docs).
      • Rotation: Erzeuge neuen Key (openssl rand -hex 32), update CI secret, redeploy Backend.
    • Hinweis: History-Rewrite ist invasiv; kommuniziere mit Team und informiere Contributors.
  10. Dokumentation

  • Ziel: Abschlussdokumentation aktualisiert.
  • Schritte:
    • Ergänze AUTHENTICATION.md um Login/Session/CSRF-Flow und Secret-Handling.
    • Ergänze FeatureRequests/FEATURE_REQUEST-security.md mit Implementations-Links (Patches/PRs).
  1. MIGRATION-GUIDE Anpassung (unbedingt)
  • Ziel: Die frontend/MIGRATION-GUIDE.md spiegelt nicht mehr den sicheren Produktions-Workflow. Sie muss aktualisiert werden, damit Entwickler/KI keine unsicheren Anweisungen (Admin-Key im Frontend) ausführen.
  • Aktueller Stand (zu prüfen): Die MIGRATION-GUIDE enthält Anweisungen, REACT_APP_ADMIN_API_KEY in frontend/.env zu setzen und dieselbe Variable an frontend im docker-compose.yml weiterzugeben. Dies steht im direkten Widerspruch zur hier geforderten serverseitigen Session-Lösung.
  • Erforderliche Änderungen in frontend/MIGRATION-GUIDE.md (konkret):
    • Entferne oder ersetze alle Anweisungen, die REACT_APP_ADMIN_API_KEY in Frontend .env oder Build-Umgebungen für Production setzen.
    • Ersetze Fetch-/Axios-Beispiele, die Authorization: Bearer ${process.env.REACT_APP_ADMIN_API_KEY} setzen, durch die neue Anleitung: Login → GET /auth/csrf-tokenfetch(..., { credentials: 'include', headers: { 'X-CSRF-Token': csrfToken } }).
    • Passe das Docker-Beispiel an: ADMIN_API_KEY darf nur dem backend-Service übergeben werden; entferne die Weitergabe an frontend (Zeile - REACT_APP_ADMIN_API_KEY=${ADMIN_API_KEY}).
    • Ersetze lokale Testanweisungen, die Frontend mit REACT_APP_ADMIN_API_KEY starten, durch Login-/Session-Testschritte (siehe Tasks 2/3/8).
    • Ergänze Hinweis zur CI/Build-Scan-Prüfung: CI muss prüfen, dass gebaute build/ keine Admin-Key-Strings enthält.
  • Abnahme: frontend/MIGRATION-GUIDE.md enthält keine Production-Anweisungen, die Admin-Secrets ins Frontend bringen; stattdessen ist der Session-Flow dokumentiert und verlinkt.

Hinweis für die Implementierung

  • Ergänze in FeatureRequests/FEATURE_REQUEST-security.md einen Link/Verweis zur überarbeiteten MIGRATION-GUIDE-Version in der PR/Release-Notes, damit Reviewer die Änderung nachvollziehen können.

Rolle der implementierenden KI/Dev

  • Erzeuge konkrete Code-Patches, führe lokale Tests aus, öffne PR mit Änderungen und Tests.
  • Stelle sicher, dass alle Abnahme-Kriterien (oben) automatisiert oder manuell prüfbar sind.

Mit diesen Aufgaben sind die vorher offenen Fragen in eindeutige, ausführbare Schritte übersetzt. Bitte bestätige, welche Aufgaben ich automatisch umsetzen soll (z. B. 1 = Compose/Docker-Änderungen; 2 = Frontend adminApi.js Patch; 3 = Backend Session+CSRF minimal-Implementierung; oder all).

Hintergrund (Ist-Stand)

  • Aktuell existieren folgende sicherheitskritische Zustände im Repository:
    • frontend/.env enthält REACT_APP_ADMIN_API_KEY in der Arbeitskopie (lokal). Die Datei ist in .gitignore und wird nicht ins Git-Repository getrackt, ist aber sensibel und darf nicht in Builds/Images gelangen.
    • docker/prod/docker-compose.yml injiziert REACT_APP_ADMIN_API_KEY=${ADMIN_API_KEY} in den frontend-Service — der Key kann so in den gebauten Frontend-Bundles landen.
    • frontend/src/services/adminApi.js liest process.env.REACT_APP_ADMIN_API_KEY und sendet den Bearer-Token clientseitig mit Admin-Requests.
    • Das Production-Frontend-Dockerfile kopiert docker/prod/frontend/config/.env in das Laufzeit-Image und führt zur Startzeit ein env.sh aus, das env-config.js erzeugt (window._env_), was sensible Werte im Browser verfügbar machen kann, falls sie in .env landen.
    • Die Moderation-Weboberfläche ist zusätzlich durch htpasswd/nginx HTTP Basic Auth geschützt — das schützt das UI, aber nicht die API-Endpoints ausreichend.

Problemstellung (warum es ein Problem ist)

  • Ein im Frontend sichtbarer Admin-Key ist öffentlich und ermöglicht Missbrauch (API-Calls mit Admin-Rechten von jedem Browser).
  • Das serverseitige Secret ADMIN_API_KEY wird derzeit in Artefakte/Images injiziert und kann geleakt werden.
  • HTTP Basic Auth vor der UI ist nützlich, aber kein Ersatz für serverseitige API-Authentifizierung; API-Endpunkte müssen eigenständig prüfen.

Ziel (Soll-Stand, aus Kundensicht)

  • Admin-Funktionen sind nur nach sicherer Anmeldung erreichbar.
  • Der geheime Admin-Key verbleibt ausschließlich auf dem Server/Backend und wird nicht in Frontend-Code, Images oder öffentlich zugängliche Dateien geschrieben.
  • Frontend kommuniziert nach Anmeldung mit dem Backend, ohne je den Admin-Key im Browser zu speichern.

Anforderungen (aus Sicht des Auftraggebers, umsetzbar durch eine KI)

  • Authentifizierung:

    • Einführung eines serverseitigen Login-Flows für Admins (Session-Cookies, HttpOnly, Secure, SameSite).
    • Nach erfolgreicher Anmeldung erhält der Admin-Browser ein HttpOnly-Cookie; dieses Cookie erlaubt Zugriff auf geschützte /api/admin/*-Endpoints.
    • Backend validiert alle /api/admin/*-Requests anhand der Session; nur dann wird mit dem internen ADMIN_API_KEY gearbeitet.
  • Secrets & Build:

    • Keine Secrets (z. B. ADMIN_API_KEY) im Frontend-Quellcode, in frontend/.env, in env-config.js oder in gebauten Bundles.
    • docker/prod/docker-compose.yml darf ADMIN_API_KEY nur dem backend-Service bereitstellen; keine Weitergabe an frontend.
    • Dockerfile des Frontends darf keine Produktion-.env kopieren, die Secrets enthält.
  • Betrieb & Infrastruktur:

    • Bestehende htpasswd-Absicherung der Admin-UI kann beibehalten werden als zusätzliche Hürde, ist aber nicht die einzige Schutzmaßnahme.
    • Empfehlung: ADMIN_API_KEY über sichere Secret-Mechanismen bereitstellen (CI/CD secret store, Docker Secrets, Swarm/K8s Secrets) — dies ist ein Hinweis, keine Pflichtanweisung.

Akzeptanzkriterien (klar messbar, für Tests durch eine KI/Dev)

  • Funktional:

    • Unauthentifizierte Requests an /api/admin/* erhalten 403 Forbidden.
    • Admin-Login-Endpoint existiert und setzt ein HttpOnly-Cookie; angemeldete Admins erreichen /api/admin/* erfolgreich.
  • Artefakte / Repo:

    • frontend-Bundle (der gebaute build/-Ordner) enthält nicht den Wert von ADMIN_API_KEY (automatischer Scan: kein Vorkommen des Key-Strings).
    • frontend/.env enthält keine REACT_APP_ADMIN_API_KEY-Zeile in Produktion; docker/prod/docker-compose.yml enthält keine Weitergabe des Keys an frontend.
  • Sicherheit & Ops:

    • Dokumentation: In AUTHENTICATION.md und in dieser Feature-Request-Datei wird der neue Login-Flow und Hinweis zum Secret-Handling vermerkt.
    • Dokumentation: In AUTHENTICATION.md und in dieser Feature-Request-Datei wird der neue Login-Flow und Hinweis zum Secret-Handling vermerkt.
    • Falls ein Key im Git-Verlauf existierte, ist die Rotation des Admin-Keys als Handlungsempfehlung dokumentiert.
    • Falls frontend/.env oder ein Admin-Key jemals in das Repository gelangt ist: Scannt die Git-History und entfernt das Secret aus der History, danach rotiert den Key. Empfohlene Tools/Schritte (kurz):
      • Finden: git log --all -S 'part-of-key' oder git grep -n "REACT_APP_ADMIN_API_KEY" $(git rev-list --all) oder nutzen truffleHog/git-secrets.
      • Entfernen aus History: git-filter-repo oder bfg-repo-cleaner (z.B. bfg --replace-text passwords.txt --no-blob-protection) — danach Force-Push in ein neues Remote (Achtung: Auswirkungen auf Contributors).
      • Key-Rotation: Erzeuge neuen ADMIN_API_KEY, setze ihn in der sicheren Backend-Umgebung (CI/CD secrets / Docker secret), redeploye Backend.
      • Hinweis: Diese Schritte sind invasiv für die Git-History; koordinieren mit Team bevor Ausführung.

Nicht-funktionale Anforderungen

  • Use Session-Cookies: Cookies müssen HttpOnly, Secure und SameSite=Strict (oder Lax falls nötig) gesetzt werden.
  • CSRF-Schutz: Bei Cookie-basierten Sessions muss ein CSRF-Schutzmechanismus vorhanden sein (z. B. double-submit-token oder CSRF-Header). Hinweis: CSRF-Mechanik ist zu implementieren, aber detaillierte Schritte sind nicht Teil dieses Requests.
  • Kompatibilität: Änderungen dürfen Entwickler-Workflows nicht unnötig blockieren; Dev-Mode-Patterns (runtime env-config.js in docker/dev) können bestehen bleiben, jedoch klar getrennt von Prod.

Hinweise für die implementierende KI / das Dev-Team (kontextbezogen)

  • Aktueller Code-Pfade von Relevanz:

    • frontend/src/services/adminApi.js — liest aktuell process.env.REACT_APP_ADMIN_API_KEY und setzt den Bearer-Token clientseitig.
    • frontend/.env — enthält aktuell REACT_APP_ADMIN_API_KEY.
    • docker/prod/docker-compose.yml — injiziert REACT_APP_ADMIN_API_KEY=${ADMIN_API_KEY} in frontend.
    • docker/prod/frontend/Dockerfile — kopiert docker/prod/frontend/config/.env in das Image und führt env.sh aus, das env-config.js erzeugt (window._env_).
    • docker/prod/frontend/config/env.sh — generiert zur Laufzeit env-config.js aus .env.
    • docker/prod/frontend/config/htpasswd — existierender Schutz der Admin-UI via nginx.
  • Erwartung an eine KI-Implementierung:

    • Verstehe die Codebasis (insbesondere frontend/src/* und backend/src/*) und identifiziere alle Stellen, die REACT_APP_ADMIN_API_KEY oder ADMIN_API_KEY verwenden oder weiterreichen.
    • Entferne clientseitige Verwendung des Admin-Keys; ersetze Aufrufe an Admin-API so, dass sie serverseitig autorisiert werden (Session-Check).
    • Verifiziere durch automatische Tests (Integrationstest oder API-Call) dass /api/admin/* ohne Session abgewiesen wird und mit Session funktioniert.

Was der Auftraggeber (Ich) erwartet — kurz und klar

  • Die Admin-Funktionen sind nur nach Anmeldung verfügbar.
  • Keine Admin-Secrets gelangen in Frontend-Bundles, Images oder öffentlich zugängliche Dateien.
  • Der existierende htpasswd-Schutz darf bestehen bleiben, ist aber nicht alleinige Sicherheitsmaßnahme.

Abnahmekriterien (für das Review durch den Auftraggeber)

  • Manuelle Überprüfung: Versuch, Admin-Endpoints ohne Login aufzurufen → 403.
  • Build-Review: gebaute Frontend-Dateien enthalten keinen Admin-Key.
  • Dokumentation aktualisiert (AUTHENTICATION.md weist auf neue Session-Flow hin).

Offene Fragen / Optionen (für Entwickler/KI) — Empfehlung und Umsetzungsdetails

  • Session-Store (empfohlen: SQLite für Single-Host, Redis für Skalierung)

    • Empfehlung für diese App: SQLite / file-basierter Session-Store (einfach zu betreiben, keine zusätzliche Infrastruktur).
    • Umsetzung (Express): benutze express-session + connect-sqlite3 (oder better-sqlite3 backend). Konfiguration:
      • Session-Cookie: HttpOnly, Secure (Prod), SameSite=Strict (oder Lax wenn externe callbacks nötig), maxAge angemessen (z. B. 8h).
      • Session-Secret aus sicherer Quelle (Backend ADMIN_SESSION_SECRET), nicht im Repo.
    • Skalierung: falls Cluster/Multiple hosts geplant, wechsle zu Redis (z.B. connect-redis) und setze Redis via Docker/K8s Secret.
  • CSRF-Mechanik (empfohlen: session-bound CSRF token + Header)

    • Empfehlung: Implementiere einen session-gebundenen CSRF-Token. Ablauf:
      1. Bei Login: generiere req.session.csrfToken = randomHex() auf dem Server.
      2. Exponiere Endpoint GET /auth/csrf-token (nur für eingeloggte Sessions), der das Token im JSON zurückgibt.
      3. Frontend ruft /auth/csrf-token nach Login (credentials: 'include') und speichert Token im JS-Scope.
      4. Bei state-changing Requests sendet Frontend X-CSRF-Token: <token> Header.
      5. Server-Middleware vergleicht Header mit req.session.csrfToken und verwirft bei Mismatch (403).
    • Vorteil: HttpOnly-Session-Cookie bleibt geschützt; Token ist an Session gebunden.
    • Alternative (schnell): Double-submit cookie (weniger robust, Token in non-HttpOnly cookie + Header); nur als kurzfristige Übergangslösung.
  • Entfernen von Admin-Key aus Frontend/Build (konkrete Änderungen)

    • frontend/src/services/adminApi.js: entferne Nutzung von process.env.REACT_APP_ADMIN_API_KEY. Passe adminRequest so an, dass credentials: 'include' verwendet wird und kein Bearer-Token gesetzt wird.
    • docker/prod/docker-compose.yml: lösche die Zeile - REACT_APP_ADMIN_API_KEY=${ADMIN_API_KEY} unter frontend.
    • docker/prod/frontend/Dockerfile: entferne COPY docker/prod/frontend/config/.env ./.env (oder stelle sicher, dass die Datei keine Secrets enthält). Vermeide Prod .env Kopie in Image.
    • docker/prod/frontend/config/env.sh: darf nur non-sensitive Werte (z. B. API_URL, APP_VERSION) schreiben; dokumentiere welche Keys erlaubt sind.
  • Secrets-Delivery / Deployment

    • Backend-Secret ADMIN_API_KEY und ADMIN_SESSION_SECRET via CI/CD Secret Store oder Docker Secrets bereitstellen.
    • Beispiel (Docker secret): erstelle Secret im Swarm/K8s und referenziere es nur im backend-Service.
  • Tests / Abnahme (automatisierbar)

    • Integrationstest 1: GET /api/admin/* ohne Session → 403.
    • Integrationstest 2: Login-Flow → setze Session-Cookie → POST /api/admin/* mit gültigem X-CSRF-Token200.
    • Build-Scan: nach Build grep -R "<part-of-admin-key>" build/ oder rg REACT_APP_ADMIN_API_KEY build/ → kein Treffer.
  • Key-Leak Reaktion

    • Falls Key geleakt: sofort Key-Rotation, dokumentiere wie (generate new key, update backend secret, redeploy), und führe Git-History-Check wie in Abschnitt oben durch.
  • Operationale Hinweise

    • Behalte htpasswd-Schutz für Admin-UI als zusätzliche Zugangskontrolle, nicht als einzige Schutzmaßnahme.
    • Dokumentiere alle Änderungen in AUTHENTICATION.md und in Release-Notes.

Diese Empfehlungen sind aus Sicht einer sicheren, pragmatischen Umsetzung gewählt: sie minimieren Infrastruktur-Overhead (SQLite) und bieten klare, testbare CSRF/SessionMechaniken. Eine implementierende KI soll die obenstehenden Punkte in konkreten CodePatches umsetzen und automatisierte Tests hinzufügen.

Kontakt / Kontext

  • Repo: Project-Image-Uploader — bestehende Struktur docker/prod, frontend/, backend/ beachten.
  • Hinweis: Diese Feature-Request-Datei benennt Missstände und Anforderungen; sie erwartet, dass ein Entwickler oder eine KI die Implementierung auf Code-Ebene vornimmt.