Uni-Verein 1.8.1 – HTTPS inklusive und umfassende Sicherheitshärtung 🔐🛡️
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.ymlsamtCaddyfilestellt 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
admin123anmeldet, 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.ymlundCaddyfilerichten 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 dasCaddyfile. 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/loginist pro IP-Adresse begrenzt (Standard 20 Anfragen pro Zeitfenster, konfigurierbar überRateLimiting:AuthLogin:PermitLimit) - 🔑 Passwortwechsel erzwungen (UV-25): Beim Login mit dem Standardpasswort
admin123erscheint 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=highlä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: nosniffundContent-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-PolicyundPermissions-Policy - 🌐 CORS (UV-28): Erlaubte Origins werden über
Cors:AllowedOriginskonfiguriert (in Produktion leer), statt jedenlocalhost-Origin zuzulassen - 🔗 Sichere Bestätigungslinks (UV-35): Die Links der Selbstregistrierung nutzen eine gespeicherte
PublicBaseUrlstatt desHost-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]undno-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.exampleenthält nur Platzhalter statt echter Schlüssel - 🧰 Abhängigkeiten (UV-40):
Serilog.Sinks.Fileist auf die stabile Version7.0.0festgelegt, das ungenutzteBCrypt.Net-Nextwurde 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-IPwird 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.ymlaktualisieren, wie in der README beschrieben. Proxy und Frontend lauschen im Container jetzt auf Port8080(der Host-Port bleibt80), daher müssennginx.confund die Compose-Datei gemeinsam ersetzt werden. Das Update-Skript erledigt das für dich logs/undreceipts/müssen für das Nicht-Root-Backend (UID1654) beschreibbar sein. Das Update-Skript kümmert sich überdocker-compose-ini.ymldarum. 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!