Files
einkaufsapp/docs/reverse-proxy.md

4.9 KiB
Raw Permalink Blame History

Betrieb hinter dem Reverse Proxy (OPNsense)

Aufbau: Browser → HTTPS → nginx auf der OPNsense → HTTP → Port 8080 auf dem Docker-Host → nginx im web-Container → api.

Drei Werte in der .env

PUBLIC_BASE_URL=https://einkauf.example.de
COOKIE_SECURE=true
FORWARDED_ALLOW_IPS=<IP des Docker-Hosts oder *>

Nach jeder Änderung docker compose up -d, nicht restart ein Neustart übernimmt keine geänderten Umgebungswerte.

PUBLIC_BASE_URL landet in jeder Verifikations-, Einladungs- und Passwort-Reset-Mail. Steht dort noch http://…:8080, führen die Links ins Leere, sobald jemand von außen klickt.

COOKIE_SECURE=true ist ab jetzt Pflicht, aber auch erst ab jetzt möglich: Ein Secure-Cookie über reines HTTP wird vom Browser verworfen, und die Anmeldung scheitert dann ohne verwertbare Meldung. Beides muss gleichzeitig umgestellt werden.

Was die OPNsense weiterreichen muss

Im nginx-Plugin unter Http(s) → Location für den Upstream:

proxy_set_header Host              $host;
proxy_set_header X-Real-IP         $remote_addr;
proxy_set_header X-Forwarded-For   $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host  $host;

X-Forwarded-Proto ist der wichtigste Wert: Ohne ihn hält die Anwendung die Verbindung für unverschlüsselt.

Zusätzlich für Server-Sent Events (ab Phase 4):

proxy_buffering off;
proxy_read_timeout 3600s;

Ohne proxy_buffering off sammelt nginx die Ereignisse und gibt sie erst gebündelt weiter die Liste aktualisiert sich dann mit Verzögerung oder gar nicht.

Client-IP fürs Rate Limiting

Mit zwei Proxys davor sieht die Anwendung ohne Weiterreichung nur die IP des web-Containers. Dann würde eine einzige IP das Limit für alle auslösen. X-Forwarded-For wird durch beide Stufen durchgereicht; uvicorn wertet es wegen --proxy-headers aus.

FORWARDED_ALLOW_IPS=* ist vertretbar, solange der api-Container keinen veröffentlichten Port hat dann kann den Header nur der web-Container setzen. Sobald du den API-Port für Debugging freigibst, gehört dort die konkrete IP hinein.

PWA-Installation

Erst über HTTPS bietet der Browser „Zur Startseite hinzufügen" an und lässt den Service Worker zu. Bei iOS ist die Installation zusätzlich Voraussetzung dafür, dass Web Push in Phase 8 überhaupt funktioniert im normalen Safari-Tab gibt es keine Benachrichtigungen.

Prüfen

curl -sI https://einkauf.example.de/ | grep -i strict-transport
curl -s  https://einkauf.example.de/readyz

Und nach der Anmeldung im Browser unter Entwicklerwerkzeuge → Anwendung → Cookies: ea_session muss Secure und HttpOnly tragen, ea_csrf nur Secure.

Kopfzeilen: was aus dem Protokoll hervorgeht

Eine Auswertung der tatsächlich ausgelieferten Antworten hat drei Punkte ergeben, die auf der OPNsense-Seite liegen.

X-XSS-Protection: 1 entfernen

Die OPNsense setzt diese Kopfzeile. Sie ist überholt: Chrome hat den zugehörigen Filter entfernt, und in den Browsern, die ihn noch kennen, kann er in Einzelfällen selbst Lücken aufreißen, indem er Teile der Seite unterdrückt. Der Wert 1 ohne mode=block ist dabei die ungünstigste Variante.

Empfehlung: im nginx-Plugin abschalten oder auf 0 setzen. Der Schutz kommt von der Content-Security-Policy, nicht von dieser Kopfzeile.

HSTS: preload passt nicht zur Laufzeit

strict-transport-security: max-age=15768000; includeSubDomains; preload

Das sind gut sechs Monate. Für die Aufnahme in die Preload-Liste verlangen die Browserhersteller mindestens ein Jahr (31536000); mit dem jetzigen Wert wird das preload schlicht ignoriert.

Entweder auf 31536000 erhöhen dann aber im Bewusstsein, dass ein Eintrag in der Preload-Liste die Domain für alle Unterdomains dauerhaft auf HTTPS festlegt und sich nur mit Monaten Vorlauf rückgängig machen lässt oder das preload weglassen.

Doppelte Kopfzeilen

X-Content-Type-Options, X-Frame-Options und Permissions-Policy kommen jeweils zweimal an: einmal vom web-Container, einmal von der OPNsense. Das ist unschädlich, aber unnötig.

Wichtiger ist, was daraus folgt: Eine doppelte Content-Security-Policy wäre nicht unschädlich. Browser wenden dann beide an und lassen nur zu, was in beiden erlaubt ist. Eine zusätzliche CSP auf der OPNsense könnte die Anwendung also lahmlegen, ohne dass eine Fehlermeldung darauf hinweist sichtbar wäre nur, dass Module oder Stile nicht laden. Derzeit setzt die OPNsense keine, das sollte so bleiben.

Die OPNsense überschreibt außerdem Referrer-Policy mit same-origin statt des strengeren no-referrer aus dem Container. Unkritisch, solange die Anwendung nicht nach außen verlinkt für die öffentlichen Listenlinks unter /s/<token> bedeutet es, dass der Token nur an die eigene Herkunft übertragen würde. Wer es strenger mag, stellt die OPNsense auf no-referrer um.