← Alle Module |
S
Sicherheit & Deployment
Betrieb & Härtung

Sicherheit & Deployment

Das IuK-Backend verarbeitet hochsensible Einsatzdaten — Personendaten Betroffener, Patientendaten und Einsatzlagebilder. Der Betrieb hinter einem gehärteten nginx-Reverse-Proxy mit HTTPS und vorgelagerter Basic-Authentifizierung ist daher dringend empfohlen und ergänzt die applikationsinterne Anmeldung um eine zusätzliche Sicherheitsebene.

TLS 1.2/1.3 Basic Auth (Shared Secret) HSTS · Security-Header Zwei Sicherheitsebenen WAF-Basisschutz
🏗️

Sicherheitsarchitektur

Zwei unabhängige Schutzschichten zwischen Internet und Datenbank

Internet Browser / Smartphone Einsatzkräfte · Betroffene TETRA-Gateway tetra_client HTTPS :443 HTTPS :443 nginx (Reverse-Proxy) Schutzschicht 1 🔒 TLS 1.2/1.3 — verschlüsselte Übertragung 🔑 Basic Auth — Shared Secret (Einsatzkräfte) 🛡️ Security-Header (HSTS, X-Frame, nosniff …) 🔕 server_tokens off — nginx-Version versteckt 🔥 WAF (Rate Limit, Methoden-Filter, Blocking) Ausnahmen (kein Basic Auth) /static/ → CSS/JS für QR-Kiosk /wsapi → TETRA (X-Api-Key) /shelter/…/self_registration → QR-Kiosk für Betroffene HTTP :3000 (nur localhost) IuK-Backend (Go · Port 3000) Schutzschicht 2 👤 Session-Auth + Rollenprüfung (admin, shelter:user …) 🏢 Tenant-Isolation — kein Mandanten-übergreifender Zugriff ⏱️ Rate-Limiting bei Login, Passwort-Reset, Self-Registration SQLite-Datenbank WAL-Modus nur über Go-App erreichbar (kein direkter Netzwerkzugriff)

Das Sicherheitskonzept basiert auf zwei unabhängigen Schutzschichten: Kompromittiert ein Angreifer eine Ebene, steht er vor der nächsten.

Schicht 1 — nginx

Abwehr auf Netzwerkebene: Verschlüsselung, Authentifizierung, Schutz-Header und WAF-Grundregeln (Rate Limiting, Methoden-Filter, Pattern Blocking) — bevor eine HTTP-Anfrage die Applikation überhaupt erreicht.

Schicht 2 — Applikation

Feingranulare Zugriffssteuerung: Benutzersessions, Rollen, Mandanten-Trennung und Schutz vor Brute-Force-Angriffen auf Endpunkt-Ebene.

🛡️

Schutzmaßnahmen im Überblick

Alle aktiven Maßnahmen und ihre Wirkung

nginx-Ebene

Maßnahme Wirkung
HTTPS / TLS 1.2–1.3Alle Verbindungen verschlüsselt — Mitlesen und Manipulation im Netz unterbunden
HSTS (2 Jahre)Browser erzwingen HTTPS dauerhaft — kein Downgrade auf HTTP möglich
Basic Auth (Shared Secret)Angreifer ohne Einsatzkräfte-Passwort sehen weder Login noch andere Seiten
X-Frame-Options: DENYVerhindert Einbindung in fremde Frames (Clickjacking-Schutz)
X-Content-Type-OptionsVerhindert MIME-Type-Sniffing durch den Browser
Referrer-PolicySchränkt Weitergabe von URL-Informationen an externe Seiten ein
server_tokens offVersteckt nginx-Version vor Angreifern (Erschwerung von Versions-Exploits)
DH-Parameter (2048 Bit)Schützt den Key-Exchange vor dem Logjam-Angriff
OCSP-StaplingSchnelle Zertifikat-Validierung ohne externe Anfrage beim Verbindungsaufbau
ssl_session_tickets offSichert Forward Secrecy — aufgezeichnete Verbindungen bleiben nach Key-Kompromiss lesbar
Permissions-PolicyDeaktiviert Geolocation, Mikrofon und Kamera für alle eingebetteten Inhalte
Rate Limiting (3 Zonen)Login 5 Req/min · authentifizierte Endpunkte 60 Req/min · öffentliche Endpunkte 120 Req/min — Überschreitung → HTTP 429
HTTP-Methoden-FilterNur GET/POST/PUT/DELETE/OPTIONS erlaubt — alle anderen Methoden (TRACE, CONNECT …) → HTTP 405
Suspicious-Pattern-BlockingBlockiert Path Traversal (..), XSS-Ansätze in URLs (<>"'), Semikolon sowie bekannte Scanner-User-Agents (sqlmap, nikto …) → HTTP 403
WAF-LoggingAlle blockierten Anfragen (400/403/405/429) werden zusätzlich nach /var/log/nginx/waf_blocked.log geschrieben

Applikations-Ebene (Go)

Maßnahme Wirkung
Session-Auth + RollenNur authentifizierte Nutzer mit passender Rolle dürfen auf Ressourcen zugreifen
Tenant-IsolationMandanten können nicht auf Daten anderer Mandanten zugreifen
Rate-LimitingBrute-Force-Schutz bei Login, Passwort-Reset und Selbstregistrierung
CSRF-SchutzFormular-Tokens verhindern Cross-Site-Request-Forgery
🔥

WAF-Grundregeln

nginx-Bordmittel ohne ModSecurity — Basisschutz gegen automatisierte Angriffe

Rate Limiting

Zone Endpunkte Limit Burst
login /login, /password_reset 5 Req/min 3
global Alle authentifizierten Endpunkte (/, /ws) 60 Req/min 20
public /static/, /shelter/…/self_registration 120 Req/min 10–50

Überschreitungen liefern HTTP 429 Too Many Requests. /wsapi ist bewusst ausgenommen — der TETRA-Client ist vertrauenswürdig und hält eine dauerhafte Verbindung.

HTTP-Methoden-Filter

Nur GET POST PUT DELETE OPTIONS werden weitergeleitet. Alle anderen Methoden (z. B. TRACE, CONNECT) erhalten HTTP 405.

Suspicious-Pattern-Blocking

URI-Muster → HTTP 403
  • .. — Path Traversal
  • < > " ' — XSS-Ansätze in URL
  • ; %3B — Semikolon (Injection-Versuche)
User-Agent-Filter → HTTP 403
  • Leerer User-Agent
  • sqlmap, nikto
  • masscan, zgrab
  • python-requests

WAF-Logging

Alle blockierten Anfragen (HTTP 400, 403, 405, 429) werden zusätzlich in ein separates Log geschrieben:

# /var/log/nginx/waf_blocked.log
203.0.113.42 - [09/Jun/2026:14:22:10 +0200] "GET /../../etc/passwd HTTP/2.0" 403 "sqlmap/1.7"
203.0.113.99 - [09/Jun/2026:14:22:11 +0200] "POST /login HTTP/2.0" 429 "Mozilla/5.0 ..."
# Live-Monitoring
sudo tail -f /var/log/nginx/waf_blocked.log
Grenzen dieser Lösung: Die WAF-Regeln arbeiten ausschließlich auf URL und Header — Injections im POST-Body (SQL, XSS) erkennt nginx ohne ModSecurity nicht. Für höhere Anforderungen: ModSecurity + OWASP Core Rule Set nachrüsten.
🚀

nginx einrichten

Schritt-für-Schritt-Anleitung für Debian/Ubuntu

1
TLS-Zertifikat beschaffen

Entweder über Let's Encrypt (öffentlich erreichbarer Server) oder ein selbstsigniertes Zertifikat der eigenen PKI (internes Netz).

# Let's Encrypt (Certbot)
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d iuk-backend.example.com
2
DH-Parameter generieren

Einmaliger Schritt, dauert ca. 1–2 Minuten. Schützt den Schlüsselaustausch vor dem Logjam-Angriff.

sudo openssl dhparam -out /etc/nginx/dhparam.pem 2048
3
nginx-Konfiguration einrichten

Die fertige Konfiguration liegt unter server/deployment/nginx.conf im Projektverzeichnis. Vor dem Kopieren den server_name und die Zertifikatspfade anpassen.

# Konfiguration kopieren
sudo cp server/deployment/nginx.conf \
    /etc/nginx/sites-available/iuk-backend.conf

# server_name und ssl_certificate-Pfade anpassen
sudo nano /etc/nginx/sites-available/iuk-backend.conf

# Aktivieren
sudo ln -s /etc/nginx/sites-available/iuk-backend.conf \
    /etc/nginx/sites-enabled/
4
Basic-Auth-Passwort setzen

Dieses Shared Secret ist allen Einsatzkräften bekannt und stellt die erste Sicherheitsebene dar. Es ist kein personenbezogenes Konto — alle Einsatzkräfte teilen denselben Zugang.

# .htpasswd erstellen (PASSWORT_HIER durch echtes Passwort ersetzen)
printf "einsatz:$(openssl passwd -apr1 'PASSWORT_HIER')\n" \
    | sudo tee /etc/nginx/.htpasswd

# Zugriffsrechte setzen
sudo chmod 640 /etc/nginx/.htpasswd
sudo chown root:www-data /etc/nginx/.htpasswd
Hinweis: Benutzername einsatz kann beliebig angepasst werden. Das Passwort sollte lang und komplex sein, aber von allen Einsatzkräften gemerkt werden können — z. B. eine Passphrase aus drei Wörtern.
5
Konfiguration testen und laden
sudo nginx -t
nginx: configuration file /etc/nginx/nginx.conf test is successful

sudo systemctl reload nginx
6
IuK-Backend als systemd-Dienst aktivieren

Die Service-Unit liegt unter server/deployment/iuk-backend.service. Der Dienst läuft als eigener unprivilegierter Benutzer iuk-backend.

sudo cp server/deployment/iuk-backend.service \
    /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now iuk-backend

# Status prüfen
sudo systemctl status iuk-backend
🔓

Öffentliche Endpunkte

Ausnahmen vom Basic-Auth-Schutz — und warum

Drei Pfadbereiche sind bewusst vom Basic-Auth-Schutz ausgenommen. Sie werden von Personen aufgerufen, die das Einsatzkräfte-Passwort weder kennen noch kennen müssen.

Pfad Erreichbar für Grund
/static/ Alle CSS/JS für die Selbstregistrierungsseite — Betroffene laden diese ohne Passwort
/wsapi TETRA-Gateway TETRA-Client authentifiziert sich selbst per X-Api-Key-Header
/shelter/{id}/{id}
/self_registration
Betroffene Personen QR-Code-Kiosk am Eingang der Betreuungsstelle — Betroffene melden sich selbst an
Wichtig: Der /shelter/…/self_registration/print-Endpunkt (QR-Code-Ausdruck für Personal) bleibt hinter Basic Auth und erfordert zusätzlich die Berechtigung shelter:guest.

Schutzmaßnahmen überprüfen

Nach dem Deployment jede Maßnahme einmalig verifizieren. HOSTNAME durch den echten Hostnamen ersetzen.

Security-Header vorhanden
curl -sI https://HOSTNAME/login \
    | grep -E "Strict-Transport|X-Frame|X-Content-Type|Referrer"

strict-transport-security: max-age=63072000; includeSubDomains
x-frame-options: DENY
x-content-type-options: nosniff
referrer-policy: strict-origin-when-cross-origin
Basic Auth erzwungen (ohne Credentials → 401)
curl -o /dev/null -w "%{http_code}\n" https://HOSTNAME/login
401
Basic Auth funktioniert (mit Credentials → 200)
curl -u einsatz:PASSWORT -o /dev/null -w "%{http_code}\n" \
    https://HOSTNAME/login
200
Selbstregistrierung öffentlich erreichbar (→ 200)
# UUID durch einen echten Wert aus der Datenbank ersetzen
curl -o /dev/null -w "%{http_code}\n" \
    https://HOSTNAME/shelter/<missionId>/<shelterId>/self_registration
200
Statische Assets öffentlich (→ 200)
curl -o /dev/null -w "%{http_code}\n" \
    https://HOSTNAME/static/css/app.css
200
/health von außen gesperrt (→ 403)
curl -u einsatz:PASSWORT -o /dev/null -w "%{http_code}\n" \
    https://HOSTNAME/health
403
Print-Endpunkt hinter Basic Auth (→ 401)
curl -o /dev/null -w "%{http_code}\n" \
    https://HOSTNAME/shelter/<missionId>/<shelterId>/self_registration/print
401
WAF: HTTP-Methoden-Filter (→ 405)
curl -u einsatz:PASSWORT -X TRACE \
    -o /dev/null -w "%{http_code}\n" https://HOSTNAME/login
405
WAF: Path Traversal blockiert (→ 403)
curl -u einsatz:PASSWORT \
    -o /dev/null -w "%{http_code}\n" "https://HOSTNAME/foo/../../etc/passwd"
403
WAF: Bekannter Scanner blockiert (→ 403)
curl -u einsatz:PASSWORT -A "sqlmap/1.7.8" \
    -o /dev/null -w "%{http_code}\n" https://HOSTNAME/login
403
WAF-Log prüfen
sudo tail -20 /var/log/nginx/waf_blocked.log
TLS-Konfiguration prüfen

Extern über SSL Labs (Ziel: Note A oder A+). Lokal ohne externe Abhängigkeit:

# testssl.sh (https://testssl.sh) lokal installieren
./testssl.sh https://HOSTNAME/
Empfehlung: Die Überprüfungen nach jedem nginx-Update und nach Zertifikatsverlängerungen wiederholen. Zertifikate über Let's Encrypt werden automatisch erneuert (Certbot-Timer) — den Status regelmäßig prüfen: sudo certbot renew --dry-run