- Add icanhazstring/composer-unused as dev dependency for dependency hygiene checks - Add German documentation (docs/) covering architecture, conventions, workflows, and developer checklists - Add API layer (ApiAuth, ApiBootstrap, ApiResponse), audit, scheduler, custom fields, and SSO services - Add Microsoft OIDC SSO, API token management, and user lifecycle features - Add swagger-ui vendor integration and OpenAPI spec - Add production Docker setup and bin/ scripts - Update composer dependencies, config, templates, and frontend assets throughout Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
6.5 KiB
6.5 KiB
Sicherheitsmodell
Letzte Aktualisierung: 2026-02-21
1) Grundprinzip
Die Anwendung kombiniert mehrere Sicherheitslayer:
- Request-Grenze (Nginx + Minty Firewall)
- Session/Auth-Guard
- Permission-Checks
- Tenant-Scope-Checks
- Endpoint-spezifische Schutzlogik (z. B. Avatar-Dateien, Exporte, Actions)
Kein einzelner Layer ist ausreichend; die Kombination ist der Schutz.
2) Authentifizierung
- Session-basierter Login.
- Optionales Remember-Me über
user_remember_tokens. - Auto-Login aus Cookie erfolgt früh in
/web/index.php. - Zentraler Login-Entry ist
login(optionallogin?tenant=<slug>für Tenant-Vorauswahl). - Unknown-Email-Verhalten im Login bleibt generisch (keine Tenant-/Account-Details vor erfolgreicher Auflösung).
Kritisch:
- Tokens sind gehasht gespeichert.
- Tokens können zentral ablaufen gelassen werden (Settings-Gefahrenzone).
3) Public vs. Protected Routes
- Public Routes werden in
/config/routes.phpmitpublic => truedefiniert. - Daraus wird zur Laufzeit
APP_PUBLIC_PATHSaufgebaut. - Alles andere ist loginpflichtig.
4) Permission-System
- Berechtigungen sind feingranular (
permissions+role_permissions). - Rollen vergeben Berechtigungen an User (
user_roles). - Actions prüfen Berechtigungen explizit.
Empfehlung:
- Rechte für View/Edit/Delete getrennt halten.
- Admin-only Endpunkte immer serverseitig absichern, nicht nur im UI verstecken.
- Onboarding-PDFs für Benutzer laufen über eigenes Recht
users.access_pdf(Single + Bulk). - Tenant-Zusatzfelder sind getrennt abgesichert:
custom_fields.managefür Definitionen/Optionen im Tenantcustom_fields.edit_valuesfür Wertepflege am User.field_keywird serverseitig erzeugt/stabil gehalten (kein editierbares UI-Feld), damit tenant-weite Eindeutigkeit erhalten bleibt.
- Theme-Wechsel für User wird tenant-spezifisch abgesichert:
- effektive Regel kommt aus
current_tenant.allow_user_theme(Fallback globalapp_theme_user) - Endpoint
admin/users/themeblockt bei deaktivierter Regel mit403(theme_disabled).
- effektive Regel kommt aus
- Tenant-Microsoft-SSO ist separat abgesichert:
tenants.sso_managefür Pflege der Tenant-SSO-Konfiguration.- Shared-App-Credentials bleiben unter
settings.update. - Secrets werden nur verschlüsselt gespeichert (
APP_CRYPTO_KEY+ AES-256-GCM), nie im Klartext gerendert. - Profil-Sync ist tenant-spezifisch konfigurierbar (
sync_profile_on_login,sync_profile_fields). - Erlaubte Sync-Felder:
first_name,last_name,phone,mobile,avatar. - Graph-basierte Felder (
phone/mobile/avatar) laufen fail-open: Login bleibt erfolgreich, auch wenn Graph nicht verfügbar ist.
5) Tenant Scope
- Datenzugriff für tenant-gebundene Inhalte erfolgt nur bei Tenant-Match.
- Departments sind genau einem Tenant zugeordnet (
departments.tenant_id). - Beim Speichern von User-Zuordnungen werden Departments serverseitig gegen die aktuell zugewiesenen User-Tenants gefiltert; ungültige Department-Zuordnungen werden entfernt.
- User-Zusatzfeldwerte werden auf Tenant-Wechsel bereinigt (Werte außerhalb der aktuell zugewiesenen Tenants werden gelöscht).
- Filterbare Zusatzfelder sind auf sichere Typen begrenzt (
select,multiselect,boolean,date); freie Texttypen werden nicht als dynamische Filter zugelassen. - Theme-Auflösung ist tenant-spezifisch:
default_themeundallow_user_themewerden jecurrent_tenantaufgelöst; ohne Tenant-Snapshot greifen globale Defaults. - SSO-Mapping bleibt tenant-scoped:
- Primär über externe Identität (
provider + tid + oid). - Fallback einmalig über E-Mail (create-or-link), danach feste Identity-Linkung.
- Domain-Allowlist (falls gesetzt) wird im Callback serverseitig erzwungen.
- Profil-Sync überschreibt nur konfigurierte Felder und ignoriert leere Quelle-Werte;
emailbleibt nach JIT-Create unverändert (insert-only).
- Primär über externe Identität (
- Lokaler/SSO-Login ist nur mit mindestens einem aktiven User-Tenant erlaubt (kein Sonderfall ohne Tenant).
- Strict/Non-Strict Verhalten über
TENANT_SCOPE_STRICT. - Inaktiv-Status von Tenants beeinflusst Sichtbarkeit (je nach Kontext).
6) Verbotene Zugriffe
- Bei fehlender Permission/Tenant-Bindung: forbidden flow (403 Seite) statt stilles Durchrutschen.
- Keine sensitiven Details in Fehlermeldungen leaken.
7) Datei-/Media-Endpunkte
- Avatar/Favicon/Logo Endpunkte prüfen Session + Zugriffskontext.
- Storage liegt außerhalb direkter Business-Logik; Zugriff nur über kontrollierte Endpunkte/Symlinks.
8) CSRF und Form-Schutz
- Schreibaktionen nutzen CSRF-Token.
- Delete/Status-Aktionen nur per POST und serverseitiger Validierung.
- Bulk-Download für Onboarding-PDF (
admin/users/access-pdf-bulk) ist POST+CSRF, Scope bleibt aktiv. - OIDC-Loginfluss nutzt
state,nonceund PKCE; Callback validiert zusätzlichaud,iss,tid, Signatur (JWKS),exp/nbf.
9) Operative Checks
Regelmäßig prüfen:
- Inaktive Rollen/Permissions werden nicht mehr aktiv zugewiesen/ausgewertet.
- Tenant-Entzüge invalidieren Sichtkontext erwartungsgemäß.
- Remember-Tokens können zentral invalidiert werden.
- Mail-Log enthält Fehlerdaten für Auditing.
- User-Lifecycle-Policy (falls aktiv) läuft täglich und setzt inaktive Accounts automatisch auf
inactivebzw. löscht sie später (2-stufig), privilegierte Admins sind ausgenommen.- Delete schreibt vorher zwingend ein Audit-Snapshot (fail-closed).
- Snapshot ist verschlüsselt gespeichert (
snapshot_enc) und enthält keine Secrets/Tokens. - Restore ist separat berechtigt (
users.lifecycle_restore) und stellt bewusst keine Assignments wieder her.
- Geplante Aufgaben (Scheduler) sind Whitelist-basiert:
- keine frei ausführbaren Shell-Kommandos aus der Datenbank.
- zentrale Rechte:
jobs.view,jobs.manage,jobs.run_now. - Runner-Lock verhindert parallele Mehrfach-Ausführung.
10) API-Audit
- Alle
/api/v1/*Requests werden zentral mit Metadaten inapi_audit_logprotokolliert. - V1 speichert keine Request-/Response-Bodies, nur Metadaten (Pfad, Status, Dauer, Scope-Kontext).
- Query-Parameter werden redacted gespeichert (z. B. Token/Secret/Password-Felder).
- Zugriff auf die Audit-UI ist über Permission
api_audit.viewabgesichert. - Retention ist auf 90 Tage ausgelegt (Bereinigung per Admin-Action oder Cron).
11) User-Lifecycle-Audit
- Lifecycle-Audit-UI ist über
user_lifecycle_audit.viewabgesichert. - Restore aus Delete-Snapshot ist getrennt über
users.lifecycle_restoreabgesichert. - Ohne gültigen Snapshot wird kein Auto-Delete ausgeführt (fail-closed).
- Retention für Lifecycle-Audit-Einträge: 365 Tage.