Feature Request: security & public fronted
This commit is contained in:
parent
6574ee0171
commit
fb4b3b95a6
289
FeatureRequests/FEATURE_REQUEST-FrontendPublic.md
Normal file
289
FeatureRequests/FEATURE_REQUEST-FrontendPublic.md
Normal file
|
|
@ -0,0 +1,289 @@
|
|||
<!--
|
||||
Feature Request: Public vs. Intranet UI/API by Subdomain
|
||||
Datei erstellt: 22.11.2025
|
||||
-->
|
||||
# Feature Request: Frontend/Public API per Subdomain
|
||||
|
||||
## Kurzbeschreibung
|
||||
|
||||
Es soll unterschieden werden, welche Funktionen der App abhängig von der aufgerufenen Subdomain verfügbar sind:
|
||||
|
||||
- `deinprojekt.meindomain.de` (extern erreichbar): Nur Uploads und das Editieren via zugewiesenem Link (Management-UUID) sollen möglich sein. Keine Moderations-, Gruppen- oder Slideshow-Funktionen sichtbar oder nutzbar.
|
||||
- `deinprojekt.lan.meindomain.de` (Intranet): Vollständige Funktionalität (Slideshow, Groupsview, Moderation, Admin-Endpunkte) sowie volle Navigation/Buttons im Frontend.
|
||||
|
||||
Die Anwendung läuft in Docker auf einem Ubuntu-Server, vorgeschaltet ist ein `nginx-proxy-manager`. Die Domain `*.lan.meindomain.de` ist nur intern erreichbar und besitzt ein gültiges SSL-Zertifikat für das Intranet.
|
||||
|
||||
Es wäre optional möglich, das public-Frontend extern zu hosten und nur die entsprechenden API-Endpunkte öffentlich verfügbar zu machen.
|
||||
|
||||
## Ziele
|
||||
|
||||
- Sicherheit: Admin-/Moderations-Funktionalität niemals über die öffentliche Subdomain erreichbar machen.
|
||||
- UX: Im öffentlichen (externen) Kontext nur die Upload-Experience sichtbar und bedienbar.
|
||||
- Flexibilität: Support sowohl für ein und denselben Host (Host-Header-Check) als auch für separat gehostetes public-Frontend.
|
||||
|
||||
## Vorschlag — Technische Umsetzung (hoher Level)
|
||||
|
||||
1) Host-Erkennung
|
||||
- Backend und Frontend erkennen die Subdomain via `Host` bzw. `X-Forwarded-Host` Header. Alternativ über eine runtime `env-config.js` (`/public/env-config.js`) die beim Request vom Backend dynamisch befüllt wird.
|
||||
|
||||
2) Backend: Gatekeeping-Middleware
|
||||
- Neue Middleware (z.B. `middlewares/hostGate.js`) prüft `req.hostname` / `x-forwarded-host`.
|
||||
- Wenn Request von öffentlicher Subdomain: schränke verfügbare API-Routen ein — nur `/api/upload` und `/api/manage/:token` (oder die minimalen Endpoints) werden zugelassen.
|
||||
- Wenn Request von interner Subdomain: volle Route-Registrierung (Admin, System, Migration usw.).
|
||||
- Schleifen-/Edge-Cases: Allowlist für einzelne externe Hosts (z. B. externe public-frontend-Host), sodass ein extern gehostetes UI die public-API nutzen darf.
|
||||
|
||||
3) Frontend: Menü- und Feature-Visibility
|
||||
- Beim Laden prüft das Frontend `window.location.host` (oder die runtime `env-config.js`).
|
||||
- Wenn public-host: Navigation reduziert — nur Upload, ggf. Hilfe/Impressum. Alle Buttons/Links zu Moderation/Slideshow/Gruppen ausgeblendet/gesperrt.
|
||||
- Wenn internal-host: komplette Navigation und Admin-Funktionen sichtbar.
|
||||
|
||||
4) Reverse Proxy / nginx
|
||||
- `nginx-proxy-manager` muss Host-Header weiterreichen (standard). Wichtig: `proxy_set_header Host $host;` so dass Backend den Host erkennt.
|
||||
- SSL: bereits vorhanden für beide Host-Namespaces (extern + lan).
|
||||
- Alternative: Public-Frontend extern hosten -> Proxy/Firewall so konfigurieren, dass nur die erlaubten API-Routen erreichbar sind (oder API-Server hinter VPN nur für `*.lan.` erreichbar).
|
||||
|
||||
5) CORS & Security
|
||||
- Public-API: enge CORS-Regel (nur erlaubte public-frontend-origin, falls extern gehostet).
|
||||
- Rate-Limiting für public Uploads stärker setzen.
|
||||
- Upload-Validierung (Dateityp, Größe), Scanner/Virus-Check bedenken.
|
||||
|
||||
## Akzeptanzkriterien (Metrisch / Testbar)
|
||||
|
||||
- Auf `deinprojekt.meindomain.de` sind nur Upload und Management-by-UUID erreichbar — Aufrufe von `/api/admin/*` erhalten 403/404.
|
||||
- Auf `deinprojekt.lan.meindomain.de` sind Admin- und Moderation-Endpunkte erreichbar und die Navigation zeigt alle Menüpunkte.
|
||||
- Unit-/Integrationstest: Backend-Middleware hat Tests für Host-Varianten (public/internal/external-frontend)
|
||||
- End-to-End: Test-Upload über public-host funktioniert, Moderation-API von dort nicht.
|
||||
|
||||
## Änderungsumfang (Konkrete Dateien/Orte)
|
||||
|
||||
- Backend
|
||||
- `src/middlewares/hostGate.js` (neu) — enthält Host-Prüfung und Policy
|
||||
- `src/server.js` / `src/index.js` — Routen nur registrieren oder mounten, falls Host-Policy es erlaubt; oder Middleware pro Route
|
||||
- `src/middlewares/auth.js` — ggf. anpassen, um Host-Checks in Kombination mit Auth zu berücksichtigen
|
||||
|
||||
- Frontend
|
||||
- `public/env-config.js` (runtime) oder `env-config.js` (build-time) — Flag `PUBLIC_MODE=true/false` bzw. `APP_ALLOWED_FEATURES`
|
||||
- Menü-Komponenten (z. B. `Components/Pages/*`) — Feature-Visibility anhand `window.location.host` oder runtime-config
|
||||
|
||||
- Infrastruktur
|
||||
- `docker/dev/*` nginx-proxy-manager Konfiguration prüfen: Host-Header, Zertifikate
|
||||
|
||||
## Sicherheits-Überlegungen
|
||||
|
||||
- Admin-Endpoints müssen serverseitig geblockt sein — niemals nur per Frontend-UI verstecken.
|
||||
- Public Uploads: individuelle Rate-Limits, Captcha-Optionen, Virus/Malware-Scanning.
|
||||
- Logging & Audit: Uploads von extern sollten besondere Logging-Flags bekommen (IP, Host, Herkunfts-Header).
|
||||
|
||||
## Fragen / Punkte zur Konkretisierung — und Antworten aus der Projektdokumentation
|
||||
|
||||
Nach Durchsicht von `README.md`, `README.dev.md`, `CHANGELOG.md` und `AUTHENTICATION.md` habe ich viele offene Punkte direkt beantwortet und die verbleibenden Entscheidungen auf das Nötigste reduziert. Unten: jeweils die Frage, was die Doku bereits festlegt, und die noch offenen Bestätigungen, die Du kurz geben solltest.
|
||||
|
||||
1. Domains — exakte Hosts
|
||||
- Dokumentation: Platzhalter-Hosts wurden als Beispiele verwendet (z. B. `deinprojekt.meindomain.de` und `deinprojekt.lan.meindomain.de`).
|
||||
- Empfehlung / Bitte bestätigen: Nenne bitte die echten Subdomains, die Dein Deployment verwenden wird. Beispiel‑Antwort reicht: `public.example.com` und `public.lan.example.com`.
|
||||
|
||||
2. Host-Check vs. zusätzliche Checks
|
||||
- Doku: Admin‑API ist bereits serverseitig per Bearer‑Token (`ADMIN_API_KEY`) geschützt. Management‑API nutzt UUID‑Token mit Rate‑Limits (10 req/h) und Brute‑Force‑Schutz.
|
||||
- Empfehlung: Primär Host‑Header (`Host` / `X-Forwarded-Host`) prüfen (einfach, zuverlässig). Zusätzlich empfehle ich für Admin‑APIs die Kombination aus Bearer‑Token + Host‑Check (defense in depth). Bitte bestätigen, ob IP‑Whitelist gewünscht ist.
|
||||
|
||||
3. Externes Hosting des public‑Frontends
|
||||
- Doku: Assets und Server liegen standardmäßig lokal (backend `src/data/images` / `src/data/previews`). Externes Hosting ist nicht Teil der Standardkonfiguration.
|
||||
- Empfehlung: Behalte Assets intern (Standard). Wenn Du extern hosten willst, müssen CORS, Allowlist und ggf. signierte URLs implementiert werden. Bestätige, ob externes Hosting geplant ist.
|
||||
|
||||
4. Management‑UUID (Editieren von extern)
|
||||
- Doku: Management‑Tokens sind permanent gültig bis Gruppe gelöscht; Token sind URL‑basiert und Rate‑limited (10 req/h). README zeigt, dass Management‑Portal für Self‑Service gedacht ist und kein zusätzliches network restriction vorgesehen ist.
|
||||
- Schlussfolgerung: Editieren per UUID ist technisch erlaubt und im Projekt vorgesehen. Wenn Du das beibehalten willst, ist keine weitere technische Änderung nötig. Falls Du TTL für Tokens möchtest, bitte angeben.
|
||||
|
||||
5. Admin‑APIs: Host‑only oder zusätzlich Bearer‑Token?
|
||||
- Doku: Admin APIs sind bereits durch Bearer‑Token geschützt (`ADMIN_API_KEY`).
|
||||
- Empfehlung: Behalte Bearer‑Token als Hauptschutz und ergänze Host‑Restriction (Admin nur intern erreichbar) für zusätzliche Sicherheit. Bitte bestätigen.
|
||||
|
||||
6. Rate‑Limits / Quotas für public Uploads
|
||||
- Doku: Management hat 10 req/h per IP; Upload‑Rate‑Limits für public uploads sind nicht konkret spezifiziert.
|
||||
- Vorschlag: Default `20 uploads / IP / Stunde` für public subdomain + strengere throttling für unauthenticated bursts. Bestätige oder nenne anderes Limit.
|
||||
|
||||
7. Logging / Monitoring
|
||||
- Doku: Es gibt umfassende Audit-Logs (`management_audit_log`, `deletion_log`).
|
||||
- Empfehlung: Ergänze ein Feld/Label `source_host` oder `source_type` für public vs. internal Uploads für bessere Filterbarkeit. Bestätigen?
|
||||
|
||||
8. Assets / CDN
|
||||
- Doku: Bilder und Previews werden lokal gespeichert; kein CDN-Flow vorhanden. Du hast klargestellt: Bilder sind intern und nur über UUID‑Links zugänglich.
|
||||
- Entscheidung: Default bleibt interne Auslieferung. Externe CDN-Auslieferung ist möglich, aber muss aus Privacy/Access‑Control‑Gründen extra implementiert (signed URLs, TTL, ACLs). Keine Aktion nötig, wenn Du interne Auslieferung beibehältst.
|
||||
|
||||
---
|
||||
|
||||
Bitte bestätige die wenigen noch offenen Punkte (Hosts, public‑group‑view ja/nein (siehe unten), Management‑UUID extern ja/nein (bestätigt als ja), desired rate‑limit, zusätzliche Admin‑restrictions, logging‑label). Ich habe die Dokumentation soweit wie möglich angepasst (siehe Änderungen weiter unten). Sobald Du diese 3–4 Punkte bestätigst, erstelle ich die konkreten Patches (Middleware, kleine Frontend‑Visibility‑Änderung, Tests, README‑Erweiterung).
|
||||
## Vorschlag: Minimal umsetzbare erste Iteration (MVP)
|
||||
|
||||
1. Implementiere `middlewares/hostGate.js` mit einfacher Host-Allowlist (`PUBLIC_HOSTS`, `INTERNAL_HOSTS` in Env).
|
||||
2. Im Backend: prüfe bei jedem Request, ob Route erlaubt ist — für public-Hosts nur Upload & manage-by-uuid.
|
||||
3. Im Frontend: beim Laden `window.location.host` prüfen und Navigation entsprechend reduzieren.
|
||||
4. Dokumentation: `README.dev.md` (API-Abschnitt) und `frontend/MIGRATION-GUIDE.md` um Hinweise erweitern.
|
||||
5. Tests: Unit-Test für Middleware + Integrationstest (Supertest) der Host-Policies.
|
||||
|
||||
## Nächste Schritte / Implementierungs-Checklist
|
||||
|
||||
- [ ] Domain-/Host-Liste bestätigen (Fragen beantworten)
|
||||
- [ ] Env-Variablen definieren und in `docker/*/config/.env` ergänzen
|
||||
- [ ] Backend: Middleware implementieren + Tests
|
||||
- [ ] Frontend: runtime `env-config.js` + menu-visibility implementieren
|
||||
- [ ] Proxy/Nginx: Konfiguration prüfen & SSL testen
|
||||
- [ ] Review & Security-Check (rate-limits, CORS, logging)
|
||||
- [ ] Deployment-Plan / Rollout-Notes
|
||||
|
||||
---
|
||||
|
||||
|
||||
Bitte beantwort e die Fragen im Abschnitt "Fragen / Punkte zur Konkretisierung" oben. Sobald ich Deine Antworten habe, kann ich ein konkretes Implementierungs-Patch (Backend-Middleware + Frontend-Visibility) erstellen und Tests hinzufügen.
|
||||
|
||||
## FAQ: Trennung von Frontend und Backend — Frage des Nutzers & Antwort
|
||||
|
||||
**Frage:**
|
||||
Wie kann ich Frontend und Backend räumlich trennen, ohne dass sicherheitsrelevante (Bilder) theoretisch extern erreichbar sind? Im Moment laufen Frontend und Backend in einer Docker Compose. Ist das sinnvoll? Wie trennt man das am Besten?
|
||||
|
||||
**Antwort (zusammengefasst & praxisorientiert):**
|
||||
|
||||
- Development: Für lokale Entwicklung ist eine gemeinsame `docker-compose`-Umgebung (Frontend + Backend) sinnvoll — HMR, einfache Debugging und Tests.
|
||||
- Produktion: Trennung empfohlen. Ziel: Frontend öffentlich (statisch/CDN) betreiben, Backend streng begrenzen und Assets (Originale/Previews) niemals ohne Authorisierung öffentlich machen.
|
||||
|
||||
Architektur-Optionen (Kurz):
|
||||
- Single-Server mit `nginx` Reverse‑Proxy (empfohlen, einfach): `nginx` routet `/` zum statischen Frontend und `/api/*` zum Backend; Backend nicht direkt öffentlich.
|
||||
- Frontend extern (CDN/Netlify) + Backend intern hinter Reverse‑Proxy: Frontend ist skalierbar, Backend nur über Proxy erreichbar; für Bilder: presigned URLs oder Backend‑Proxy verwenden.
|
||||
- Vollständige Trennung (Backend nur im privaten Netz / VPN): Sehr sicher, aber komplexer (VPN/VPC). Admin-/Moderation nur über LAN/VPN erreichbar.
|
||||
|
||||
Wie Bilder sicher halten (Pattern):
|
||||
- Pattern A — Backend‑proxied images: Bilder nur auf Backend speichern; Zugriff nur über Backend‑Endpunkte (prüfen Management‑UUID / Host), keine direkte öffentliche URL.
|
||||
- Pattern B — Private Object Storage + presigned URLs: Nutze privaten S3/Bucket; generiere kurzlebige presigned URLs nach Auth/Zugriffsprüfung; kombiniere mit CDN (Origin Access).
|
||||
- Pattern C — CDN + signed URLs für Previews: Nur Previews via CDN mit signed URLs; Originals bleiben intern oder ebenfalls presigned.
|
||||
|
||||
Konkrete Maßnahmen (umsetzbar sofort):
|
||||
1. Reverse‑Proxy (`nginx`) einführen: zwei vhosts (public / internal). Auf public vhost `/api/admin` und `/groups` blockieren; nur `/api/upload` und `/api/manage/:token` erlauben.
|
||||
2. Docker‑Netzwerke: Backend in `internal_net` ohne veröffentlichte Ports; `reverse-proxy` hat öffentliche Ports und verbindet zu `backend` intern.
|
||||
3. Host‑Gate Middleware (Express): `req.isPublic` setzen via `Host`/`X-Forwarded-Host`, serverseitig Routen (Admin/Groups) für public blocken — defense in depth.
|
||||
4. CORS & Rate‑Limit: CORS auf erlaubte Origins, strengere Rate‑Limits für public Uploads (z. B. 20 Uploads/IP/Stunde) und Captcha prüfen.
|
||||
5. Logging: Audit‑Logs erweitern (z. B. `source_host`) um public vs internal Uploads zu unterscheiden.
|
||||
|
||||
Beispiel nginx‑Snippet (konzeptionell):
|
||||
|
||||
```
|
||||
server {
|
||||
server_name public.example.com;
|
||||
location / { root /usr/share/nginx/html; try_files $uri /index.html; }
|
||||
location ~ ^/api/(upload|manage) { proxy_pass http://backend:5001; proxy_set_header Host $host; }
|
||||
location ~ ^/api/admin { return 403; }
|
||||
location ~ ^/groups { return 403; }
|
||||
}
|
||||
|
||||
server {
|
||||
server_name internal.lan.example.com;
|
||||
location / { proxy_pass http://frontend:3000; }
|
||||
location /api/ { proxy_pass http://backend:5001; }
|
||||
}
|
||||
```
|
||||
|
||||
Docker‑Compose Hinweis (prod): Backend ohne `ports:` veröffentlichen; `reverse-proxy` expose Ports 80/443 und verbindet intern:
|
||||
|
||||
```
|
||||
services:
|
||||
reverse-proxy:
|
||||
ports: ["80:80","443:443"]
|
||||
networks: [public_net, internal_net]
|
||||
backend:
|
||||
networks: [internal_net]
|
||||
# no ports
|
||||
networks:
|
||||
internal_net:
|
||||
internal: true
|
||||
```
|
||||
|
||||
Checklist (schnell umsetzbar)
|
||||
- [ ] `nginx` reverse‑proxy hinzufügen
|
||||
- [ ] Backend‑Ports entfernen (nur interner Zugriff)
|
||||
- [ ] vhost‑Regeln: public vs internal (Admin blockieren auf public)
|
||||
- [ ] `hostGate` middleware implementieren (Express)
|
||||
- [ ] CORS, Rate‑Limit, Captcha konfigurieren
|
||||
- [ ] Audit‑Log `source_host` ergänzen
|
||||
|
||||
Wenn Du möchtest, implementiere ich als nächsten Schritt die `hostGate`‑Middleware, Beispiel‑nginx‑VHosts und die `docker-compose`‑Änderungen als Patch hier im Repository. Sag mir kurz, welche Hostnames (Platzhalter sind OK) und ob Du Frontend lokal im selben Host behalten willst oder extern hosten willst.
|
||||
|
||||
## Technische Details & Voraussetzungen
|
||||
|
||||
Im Folgenden findest Du eine vertiefte, technische Zusammenfassung der Architekturoptionen, Voraussetzungen und Sicherheitsmaßnahmen — als Entscheidungsgrundlage für die Implementierung des Subdomain‑abhängigen Verhaltens.
|
||||
|
||||
1) Ziel und Sicherheitsprinzip
|
||||
- Zweck: Subdomain‑abhängig unterschiedliche UX und API‑Zugänglichkeit (Public: Upload + Manage-UUID; Intranet: Full‑Feature).
|
||||
- Sicherheitsprinzip: Nie ausschließlich auf Frontend‑Steuerung vertrauen — serverseitige Blockierung ist Pflicht.
|
||||
|
||||
2) Infrastruktur‑Varianten
|
||||
- Variante A — Single Host + `nginx` Reverse‑Proxy: Einfach, kontrollierbar, Proxy hostet TLS, routet an Backend; Backend nicht direkt erreichbar.
|
||||
- Variante B — Frontend extern (CDN/Netlify) + Backend intern: Skalierbar; Bilder per presigned URLs oder Backend‑Proxy ausliefern.
|
||||
- Variante C — Backend nur im privaten Netz/VPN: Höchste Sicherheit, mehr Betriebskomplexität.
|
||||
|
||||
3) Host‑Erkennung und Defense in Depth
|
||||
- Proxy muss `Host` bzw. `X-Forwarded-Host` weiterreichen (`proxy_set_header Host $host`).
|
||||
- Implementiere serverseitig eine `hostGate`‑Middleware, die `req.isPublic` bzw. `req.isInternal` setzt und schütze kritische Routen zusätzlich (Admin, Groups Listing, Cleanup).
|
||||
- Kombiniere Proxy‑Regeln + Middleware + Bearer‑Token (für Admin) + Firewall für maximale Sicherheit.
|
||||
|
||||
4) Speicherung und Auslieferung von Bildern
|
||||
- Standard: Bilder lokal in `backend/src/data/images` und `.../previews`.
|
||||
- Pattern A (empfohlen kleinbetrieblich): Backend‑proxied images — keine direkten öffentlichen Pfade; Backend kontrolliert Zugriffe (UUID, Host).
|
||||
- Pattern B (Skalierung): Privater Object‑Store (S3‑compatible) + presigned URLs (TTL kurz) + CDN (Origin Access) für Performance.
|
||||
- Previews können weniger restriktiv gehandhabt werden (kurze TTLs / signed URLs), Originals sollten restriktiver sein.
|
||||
|
||||
5) Management‑UUID (Risiken & Optionen)
|
||||
- Aktuell: UUIDs permanent gültig bis Löschung (convenience). Risiko: Leak bedeutet Zugriff.
|
||||
- Optionen: Beibehalten + Rate‑Limit/Audit (empfohlen), oder TTL/Rotation/Opt‑in Passwortschutz (sicherer, schlechtere UX).
|
||||
|
||||
6) CORS, CSRF, TLS
|
||||
- CORS: Nur erlaubte Origins eintragen (public frontend origin(s) und/oder intranet origin).
|
||||
- CSRF: REST API mit token/UUID im Pfad ist weniger CSRF‑anfällig, trotzdem sicherheitsbewusst durchführen.
|
||||
- TLS/HSTS: Pflicht für öffentliche Hosts.
|
||||
|
||||
7) Rate‑Limiting und Abuse‑Protection
|
||||
- Public Uploads streng limitieren (z. B. 20 uploads/IP/Stunde) + Dateigrößenlimits + MIME/Exif/Type‑Validation.
|
||||
- Optional Captcha für Uploads bei hohem Traffic/Abuse Verdacht.
|
||||
|
||||
8) Logging und Monitoring
|
||||
- Ergänze Audit‑Logs um `source_host`/`source_type` und `request_origin`.
|
||||
- Metriken für rate‑limit hits, 403s, upload errors, health checks; optional Sentry/Prometheus.
|
||||
|
||||
9) Docker/Bereitstellungsempfehlungen
|
||||
- Dev: `docker/dev/docker-compose.yml` mit exposed ports OK.
|
||||
- Prod: Backend keinem Hostport aussetzen (`ports:` entfernen). Reverse‑proxy exponiert 80/443; backend nur im internen Docker‑Netz.
|
||||
- Verwende ein `internal` Docker‑Netzwerk oder separate Netzwerke für Public/Private.
|
||||
|
||||
10) nginx‑proxy‑manager Hinweise
|
||||
- Konfiguriere Proxy‑Hosts für public vs. internal mit passenden Headern (`Host`, `X-Forwarded-*`).
|
||||
- Verwende Proxy‑Regeln, um `/api/admin` & `/groups` auf public Host zu blocken; teste mit `curl`.
|
||||
|
||||
11) Deployment‑Prerequisites (konkret)
|
||||
- DNS für beide Subdomains (public + intranet) vorhanden.
|
||||
- TLS für public (Let's Encrypt) und internes Zertifikat für LAN.
|
||||
- `ADMIN_API_KEY` sicher gesetzt, `PUBLIC_HOSTS` / `INTERNAL_HOSTS` konfiguriert.
|
||||
- Backup‑/Restore‑Policy für DB & images.
|
||||
|
||||
12) Entscheidungsfragen / Tradeoffs
|
||||
- UUID permanent vs TTL: UX vs Security.
|
||||
- Previews via CDN vs Backend‑Proxy: Performance vs Kontrolle.
|
||||
- Frontend lokal hinter nginx vs extern gehostet: Einfachheit vs Skalierbarkeit.
|
||||
|
||||
13) Prüfbare Akzeptanzkriterien (Beispiele)
|
||||
- `curl -I https://public.example.com/api/admin/deletion-log` → 403
|
||||
- Upload via public Host funktioniert (POST to `/api/upload`), Moderation API returns 403.
|
||||
- Backend nicht per `docker ps`/published port extern erreichbar.
|
||||
|
||||
14) Vorschlag: nächste non‑implementierende Schritte
|
||||
- Definiere endgültig: Public/Internal Hostnames; Management‑UUID Policy (TTL ja/nein); Rate‑Limit Wert; CDN für Previews ja/nein.
|
||||
- Ich kann danach ein Security‑Design‑Dokument (nginx rules, env vars, checklist) erstellen oder direkt Implementierungs‑Patches liefern.
|
||||
|
||||
Bitte bestätige kurz die vier entscheidenden Punkte, damit ich das Design final zuspitze:
|
||||
- Hosts: welche Subdomains sollen verwendet werden? (z. B. `deinprojekt.meindomain.de`, `deinprojekt.lan.meindomain.de`)
|
||||
- Management‑UUID extern erlaubt? (Ja/Nein)
|
||||
- Rate‑Limit für public Uploads? (z. B. `20 uploads/IP/Stunde`)
|
||||
- Previews via CDN erlaubt? (Ja/Nein)
|
||||
|
||||
---
|
||||
|
||||
Bitte sag mir, ob ich diese detaillierte Sektion so übernehmen soll (ich habe sie bereits in dieses Feature‑Request eingefügt). Wenn ja, kann ich auf Wunsch noch ein kurzes Security‑Design‑PDF oder konkrete nginx‑Snippet‑Dateien ergänzen.
|
||||
|
||||
<!-- Ende Feature Request -->
|
||||
243
FeatureRequests/FEATURE_REQUEST-security.md
Normal file
243
FeatureRequests/FEATURE_REQUEST-security.md
Normal file
|
|
@ -0,0 +1,243 @@
|
|||
<!--
|
||||
Feature Request: Server-seitige Session-Authentifizierung für Admin-API
|
||||
Zielgruppe: Entwickler / KI-Implementierer
|
||||
-->
|
||||
|
||||
# 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`:
|
||||
```js
|
||||
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).
|
||||
|
||||
11) 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-token` → `fetch(..., { 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-Token` → `200`.
|
||||
- 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/Session‑Mechaniken. Eine implementierende KI soll die obenstehenden Punkte in konkreten Code‑Patches 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.
|
||||
|
||||
---
|
||||
Loading…
Reference in New Issue
Block a user