Zum Hauptinhalt springen

Uni-Verein 1.8.1 – HTTPS inklusive und umfassende Sicherheitshärtung 🔐🛡️

· 5 Minuten Lesezeit
René Herrmann
Senior developer

Veröffentlicht am 26. September 2026

Uni-Verein 1.8.1 ist ein Sicherheits-Release: Die Installation bekommt HTTPS direkt ab Werk, der Login wird deutlich robuster gegen Angriffe, Uploads werden strenger geprüft und alle Container laufen ohne Root-Rechte.

Highlights​

  • 🔐 HTTPS ab Werk: Eine neue docker-compose-tls.yml samt Caddyfile stellt Caddy vor den Stack und holt automatisch ein Let's-Encrypt-Zertifikat. Das ist jetzt der empfohlene Installationsweg
  • 🛡️ Gehärteter Login: Rate-Limiting pro IP, keine Rückschlüsse mehr darauf, ob ein Benutzername existiert, und Sperren dauern höchstens 15 statt bis zu 24 Stunden
  • 🔑 Kein Standard-Admin-Passwort mehr im Einsatz: Wer sich mit admin123 anmeldet, muss zuerst ein neues Passwort setzen
  • 📦 Sicherere Uploads und Container: Belegdateien werden anhand ihres tatsächlichen Inhalts geprüft, Upload-Größen sind begrenzt, alle Container laufen als Nicht-Root-User

Neue Funktionen​

  • 🔐 HTTPS mit Let's Encrypt (UV-27): docker-compose-tls.yml und Caddyfile richten automatisches HTTPS ein (erfordert einen DNS-Eintrag sowie die Ports 80 und 443). Der Selbst-Update-Ablauf erkennt und unterstützt beide Varianten und aktualisiert auch das Caddyfile. nginx ermittelt die echte Client-IP hinter Caddy, damit Rate-Limiting und Audit-Logs weiter funktionieren
  • 🚦 Rate-Limiter für den Login (UV-31): /auth/login ist pro IP-Adresse begrenzt (Standard 20 Anfragen pro Zeitfenster, konfigurierbar über RateLimiting:AuthLogin:PermitLimit)
  • 🔑 Passwortwechsel erzwungen (UV-25): Beim Login mit dem Standardpasswort admin123 erscheint ein Dialog, der sich erst nach dem Setzen eines neuen Passworts schließen lässt
  • 🔍 Automatische Abhängigkeitsprüfung (UV-42): npm audit --audit-level=high läuft in der CI, dazu kommt Dependabot (ein gebündelter wöchentlicher PR, keine Major-Updates)

Verbesserungen​

  • 🔒 Authentifizierung als Standard (UV-41): Alle Endpunkte erfordern jetzt standardmäßig eine Anmeldung. Bewusst öffentliche Endpunkte (Login, Selbstregistrierung, öffentliche Seitenkonfiguration, /health) sind ausdrücklich freigegeben
  • ⏱️ Fairere Sperren (UV-45): Fehlversuche beim Login verfallen nach 15 Minuten, und die Sperre ist auf maximal 15 Minuten begrenzt (vorher bis zu 24 Stunden)
  • 👤 Admin-Schutz (UV-25): Der Standard-Admin wird nur noch angelegt, wenn noch gar kein Benutzer existiert. Admins können sich nicht mehr selbst löschen oder ihre eigene Rolle ändern
  • 🧾 Uploads nach Inhalt prüfen (UV-32): Belegdateien werden anhand der Magic Bytes (PNG, JPEG, GIF, WebP, PDF) validiert statt anhand des vom Browser gemeldeten Typs. SVG und unbekannte Formate werden abgelehnt. Downloads senden X-Content-Type-Options: nosniff und Content-Disposition: attachment
  • 📏 Upload-Limits (UV-43): Das globale Request-Limit sinkt von 10 GB auf 100 MB, nur die Backup-Wiederherstellung behält 10 GB. Belegdateien und der CSV-Import der Mitglieder sind auf 10 MB pro Datei begrenzt, zu große PDFs werden schon im Browser abgelehnt
  • 🧱 Security-Header (UV-33): Beide nginx-Konfigurationen senden CSP, X-Frame-Options, nosniff, Referrer-Policy und Permissions-Policy
  • 🌐 CORS (UV-28): Erlaubte Origins werden über Cors:AllowedOrigins konfiguriert (in Produktion leer), statt jeden localhost-Origin zuzulassen
  • 🔗 Sichere Bestätigungslinks (UV-35): Die Links der Selbstregistrierung nutzen eine gespeicherte PublicBaseUrl statt des Host-Headers der Anfrage, sodass keine Phishing-Links über gefälschte Hosts möglich sind
  • 📦 Container ohne Root (UV-37): Alle Container laufen als Nicht-Root-User, mit cap_drop: [ALL] und no-new-privileges, wo es möglich ist
  • 🗝️ Geheimnisse (UV-38, UV-39): Das Init-Skript erzeugt zufällige Datenbank-Passwörter und gibt nur noch die Namen der .env-Schlüssel aus, nicht deren Werte. .env.example enthält nur Platzhalter statt echter Schlüssel
  • 🧰 Abhängigkeiten (UV-40): Serilog.Sinks.File ist auf die stabile Version 7.0.0 festgelegt, das ungenutzte BCrypt.Net-Next wurde entfernt, dazu Minor-/Patch-Updates für Backend und Frontend

Fehlerbehebungen​

  • 🖥️ Weißer Bildschirm nach dem Login (UV-18): Nach einem Update konnten veraltete, nachgeladene Programmteile einen leeren Bildschirm verursachen. Die App lädt jetzt automatisch neu, sobald ein neuer Service Worker übernimmt
  • 🔔 Firmware-Hinweis (UV-46): Der Hinweis auf ein Firmware-Update vergleicht jetzt echte Versionsnummern und erscheint nur, wenn tatsächlich eine neuere Version existiert
  • 🕵️ Benutzernamen-Enumeration (UV-44): Die Antwortzeit beim Login verrät nicht mehr, ob ein Benutzername existiert. Rohe Benutzernamen werden nicht mehr ins Log geschrieben
  • 🌍 Gefälschte IP-Header (UV-34): X-Real-IP wird nur noch aus privaten bzw. internen Netzen akzeptiert, damit sich IP-basierte Limits nicht mit einem gefälschten Header umgehen lassen

⚠️ Hinweise zum Update​

  • Immer mit docker-compose-update.yml aktualisieren, wie in der README beschrieben. Proxy und Frontend lauschen im Container jetzt auf Port 8080 (der Host-Port bleibt 80), daher müssen nginx.conf und die Compose-Datei gemeinsam ersetzt werden. Das Update-Skript erledigt das für dich
  • logs/ und receipts/ müssen für das Nicht-Root-Backend (UID 1654) beschreibbar sein. Das Update-Skript kümmert sich über docker-compose-ini.yml darum. Bei einer manuellen Installation: chown -R 1654:1654 logs receipts
  • Wer die Selbstregistrierung nutzt: War sie schon vor dem Update aktiviert, muss ein Admin einmal die allgemeinen Einstellungen öffnen und speichern. Dabei wird die öffentliche URL für die Bestätigungslinks hinterlegt. Bis dahin schlagen neue Anmeldungen fehl
  • Die Datenbank-Migration (AddLastFailedLoginAttemptAndPublicBaseUrl) läuft beim Start automatisch

Warum diese Updates wichtig sind​

Ein Vereinssystem verwaltet Namen, Adressen und Bankdaten und sollte daher so sicher betrieben werden wie möglich. Mit HTTPS ab Werk, einem robusteren Login und strengeren Prüfungen bei Uploads und Netzwerkzugriffen schließt 1.8.1 gleich eine ganze Reihe möglicher Angriffsflächen. Dass die Container jetzt ohne Root-Rechte laufen, begrenzt zudem den Schaden, falls doch einmal etwas schiefgeht.

Wie geht es weiter?​

Weiteres Feedback aus der Praxis ist wie immer herzlich willkommen, gerne über GitHub Issues. Schaut auch weiterhin gerne hier vorbei!