Vier Luecken geschlossen, die im Alltag sofort aufgefallen waeren:
- Passwort aendern war im eingeloggten Zustand gar nicht moeglich; es gab
nur den Reset per Mail-Link. saas_change_password() prueft das aktuelle
Passwort, verlangt ein tatsaechlich anderes und erneuert danach die
Session-ID. Formular in konto.php.
- mandant-auswahl.php war nur direkt nach dem Login erreichbar. Wer bei
mehreren Mandanten Mitglied ist, musste sich zum Wechseln abmelden. Die
Seite bedient jetzt beide Wege, die Mandantenpruefung bleibt unveraendert
ueber saas_identity_for_user_tenant(). Menuepunkt ab zwei Mitgliedschaften.
- email_verified_at wurde nirgends geprueft, nur angezeigt - bei offener
Selbstregistrierung konnte sich jemand mit fremder Adresse anmelden und
alles nutzen. Erzwungen wird jetzt gezielt dort, wo eine Aktion nach
aussen wirkt: Einladung, Info-Mail, Jahresabschluss. Der Login selbst
bleibt bewusst frei, sonst waeren alle migrierten Bestandsnutzer mit
NULL-Verifikation ausgesperrt. Zusaetzlich setzt der Passwort-Reset die
Verifikation mit, weil der Mail-Link den Postfachzugriff nachweist -
sonst blieben eingeladene Mitglieder dauerhaft unbestaetigt.
- Login landete auf konto.php statt auf dem Dashboard.
Landingpage: die gruene Vertrauenszeile auf "DSGVO-konform" gekuerzt, die
Eintraege zu Paragraf 19 UStG und "Bestehende Ablaeufe bleiben" entfernt.
Geprueft: neues scripts/check-konto-und-mandantenwechsel.php mit 18
Assertions gruen, Passwortformular zusaetzlich manuell inkl. CSRF (419).
Bestehende Suiten unveraendert gruen: HTTP-Smoke 34 Seiten, Rollenmatrix
55, Mandanten-Isolation 12, M3-Auth 9, M3-Settings 15.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
datenschutz.php: Entwurf, der die tatsaechliche technische Verarbeitung
beschreibt (Konto- vs. Teilnehmerdaten, Verantwortlicher/Auftrags-
verarbeiter-Trennung, Rechtsgrundlagen, Aufbewahrungspflichten nach
HGB/AO als Begruendung fuer Anonymisieren-statt-Loeschen, Betroffenen-
rechte mit Verweis auf den Selbstbedienungs-Export). Wie AGB deutlich
als pruefungsbeduerftiger Entwurf gekennzeichnet.
preise.php: neue oeffentliche Preisliste mit den vorgeschlagenen Stufen
(gratis bis 10, 3,99 EUR bis 25, 7,99 EUR bis 50, 12,99 EUR bis 150,
auf Anfrage darueber).
Kleinunternehmer-Korrektur (kein Umsatzsteuerpflichtiger mehr):
- impressum.php: USt-IdNr-Zeile entfernt, Hinweis nach Paragraf 19 UStG ergaenzt.
- agb.php Paragraf 4: keine festen Preise mehr im Text, stattdessen Verweis
auf preise.php; "zzgl. USt" durch Kleinunternehmer-Hinweis ersetzt.
Footer-Links auf allen oeffentlichen und internen Seiten um Datenschutz
und Preise ergaenzt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
impressum.php: Angaben aus https://ctb-it.de/impressum/ uebernommen
(Clemens Creutzburg, Einzelunternehmer, USt-IdNr DE347068189), Anschrift
auf die aktuelle Adresse (In den Sieben Stuecken 9d, 30655 Hannover)
aktualisiert.
agb.php: Entwurf fuer ein B2B-SaaS-Vertragsverhaeltnis (Leistungs-
beschreibung, gestaffelte Preise nach Teilnehmerzahl, Verfuegbarkeit,
AVV-Verweis, Kuendigung, Haftungsbegrenzung), deutlich als Entwurf
gekennzeichnet mit Empfehlung zur anwaltlichen Pruefung vor
Produktivbetrieb - keine rechtssichere Fertigstellung durch mich.
Footer-Links auf Impressum/AGB ergaenzt: alle Public-Seiten (Landing,
Login, Registrierung, Passwort-Reset, E-Mail-Verifizierung) sowie der
App-interne Footer fuer eingeloggte Seiten, damit die Impressumspflicht
(leichte Erreichbarkeit von jeder Seite) erfuellt ist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Erste drei Bausteine der Haertung:
- Security-Headers (X-Content-Type-Options, X-Frame-Options, Referrer-
Policy, Permissions-Policy, HSTS bei HTTPS) laufen automatisch ueber
app_send_security_headers() am Ende von app/bootstrap.php fuer jede
dynamische Seite; landing.php war als einzige Seite ganz ohne PHP und
bekam einen minimalen Bootstrap-Aufruf. Bewusst kein CSP, da die
bestehenden Templates durchgaengig auf Inline-style-Attribute setzen.
- DB-gestuetzte Rate-Limits (neue Tabelle rate_limit_attempts) fuer
Login (10/15min je E-Mail, 20/15min je IP), Registrierung (5/h je IP)
und Passwort-Reset-Anfrage (5/h je E-Mail, 10/h je IP); bei
ausgereiztem Reset-Limit erscheint dieselbe generische Meldung wie im
Erfolgsfall, um kein Konto-Enumeration-Signal zu geben.
- Zentrales Audit-Log (neue Tabelle audit_log) fuer Mitgliederverwaltung,
Zugangsvergabe/-entzug, Storno, Mandant-Einstellungen, Hinweise,
CSV-Import, Jahresbonus-Verteilung und Live-Mailversand; sichtbar fuer
Owner/Admin auf mandant-einstellungen.php.
Live getestet: Rate-Limit greift nach 10 Fehlversuchen, Audit-Log-Eintrag
mit korrekten Metadaten und Nutzernamen ueber einen isolierten Test-
Mandanten geprueft. Alle Regressionstests weiterhin gruen (26/26 Smoke,
104 Golden-Master-Assertions).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- gemeinsames Public-CSS fuer Landingpage und Auth-Seiten ergaenzen
- Login, Registrierung und Passwort-/E-Mail-Seiten vom App-Layout trennen
- App-Sidebar von Public-Login- und Registrierungslinks bereinigen
- Webspace- und Subdomain-Strategie dokumentieren
- Auth-Token-Tabelle mit gehashten Single-Use-Tokens einführen
- Passwort-Reset und E-Mail-Verifikation als Dev-Flow bauen
- Token-Flow-Test, Smoke-Abdeckung und M3-Dokumentation aktualisieren