Eviworx
Docs

Security Architecture

Die Security-Architektur basiert auf Defense-in-Depth mit 8 Security-Layern: Transport Security (TLS 1.2+ via Traefik), Application Security (RBAC, JWT), Data Security (SHA-256 Audit-Chain, AES-256 Encryption), Container Security (Zero-Trust, Least-Privilege), File Security (ClamAV Virus-Scan), API Security (SSRF-Protection, Rate-Limiting), Authentication (SSO, native MFA/TOTP, FIPS 140-2 kompatibel) und Audit & Compliance-Unterstützung (ISO 27001, DSGVO).

🔒
Funktionen
✓ FIPS 140-2 kompatibel (keine Zertifizierung)
✓ Native MFA/TOTP (HMAC-SHA256)
✓ Entra ID SSO mit MFA (Gruppe → Rolle)
✓ Traefik-Gateway (TLS 1.2/1.3, HSTS, CSP)
✓ Rate-Limits an Gateway und in der Anwendung
✓ RBAC (28+ Module, 350+ Einzelrechte)
✓ Audit-Kette mit Manipulationserkennung (SHA-256)
✓ Zero-Trust-Virenscan (ClamAV)
✓ Gespeicherte Secrets verschlüsselt (AES-256-GCM)
✓ SSRF-Schutz (Webhooks, Workflow-Actions)

Security-Layer Übersicht

┌────────────────────────────────────────────────────────────────────────┐
│                DEFENSE-IN-DEPTH (8 LAYER)                        │
└────────────────────────────────────────────────────────────────────────┘

Layer 1: TRANSPORT SECURITY (Traefik API-Gateway)
┌──────────────────────────────────────────────────────────────────────┐
│ • TLS 1.2/1.3 only (no SSLv3, TLS 1.0, TLS 1.1)                     │
│ • Strong Ciphers: ECDHE-RSA-AES-GCM, ECDHE-ECDSA, ChaCha20-Poly1305 │
│ • HSTS: max-age=31536000; includeSubDomains; preload                 │
│ • HTTP → HTTPS Redirect (Traefik entrypoint redirect)                │
│ • Rate-Limiting: 100 req/s, burst 200 (Traefik middleware)           │
│ • Internal service interfaces blocked externally (priority routing)  │
│ • Cloudflare Turnstile CAPTCHA (Bot Protection)                      │
└──────────────────────────────────────────────────────────────────────┘

Layer 2: APPLICATION SECURITY
┌──────────────────────────────────────────────────────────────────────┐
│ • JWT Authentication (HttpOnly Cookies)                              │
│ • RBAC: 28+ Permission-Module, 350+ Individual Permissions           │
│ • Permission cache per role, writes always fresh from DB             │
│ • Permissions loaded per request, not from token                     │
│ • CSP Headers via Traefik: default-src 'self', script-src 'self'     │
│ • X-Frame-Options: SAMEORIGIN                                        │
│ • X-Content-Type-Options: nosniff                                    │
│ • X-XSS-Protection: 1; mode=block                                    │
│ • Referrer-Policy: strict-origin-when-cross-origin                   │
│ • Permissions-Policy: geolocation=(self), microphone=(), camera=()   │
│ • CSRF Protection (built-in)                                         │
└──────────────────────────────────────────────────────────────────────┘

Layer 3: DATA SECURITY
┌──────────────────────────────────────────────────────────────────────┐
│ • SHA-256 Audit-Chain (immutable, tamper-evident)                    │
│ • PII-Scrubbing (Passwords, Tokens auto-redacted)                    │
│ • AES-256-GCM Encryption (License-Keys, TOTP, alle Credentials)     │
│ • Optimistic Locking (version field prevents concurrent mods)        │
│ • Soft-Delete (Recovery-Window)                                      │
└──────────────────────────────────────────────────────────────────────┘

Layer 4: CONTAINER SECURITY
┌──────────────────────────────────────────────────────────────────────┐
│ • Read-only Filesystem (av-worker)                                   │
│ • Capability-Drop ALL (av-worker)                                    │
│ • Capability-Drop 3 (ClamAV: NET_RAW, SYS_ADMIN, MKNOD)             │
│ • Non-root Users (all workers: UID 1001)                             │
│ • no-new-privileges (Traefik, ClamAV, av-worker)                     │
│ • tmpfs for temporary storage (in-memory, volatile)                  │
│ • Resource-Limits (ClamAV: 2GB, av-worker: 1.5GB)                    │
│ • Redis Password Authentication (--requirepass)                      │
└──────────────────────────────────────────────────────────────────────┘

Layer 5: FILE SECURITY
┌──────────────────────────────────────────────────────────────────────┐
│ • Zero-Trust Virus-Scan (ClamAV, av-worker has NO file access)       │
│ • Scan-Status-Tracking: PENDING → SCANNING → CLEAN/INFECTED          │
│ • Quarantine-Volume (infected files isolated)                        │
│ • Extension-Blacklist (.exe, .bat, .sh, .dll, .js, .vbs)            │
│ • MIME-Type Validation (server-side)                                 │
│ • File-Size-Limits (Global: 100MB, per-Entity configurable)          │
│ • Max-Files-Limit (per entity)                                       │
│ • Retention-Policy (Auto-Delete after X days)                        │
│ • Orphan-Cleanup (unused files after 24h)                            │
└──────────────────────────────────────────────────────────────────────┘

Layer 6: API SECURITY
┌──────────────────────────────────────────────────────────────────────┐
│ • SSRF Protection (Webhooks, Workflow-Actions, Teams-URLs)           │
│ • HMAC Signature (webhooks with shared secret)                       │
│ • Rate-Limiting (alle Werte ENV-bar):                                  │
│   - Traefik Gateway: 100 req/s, burst 200                            │
│   - Global /api/*: 2000/min/IP · Critical-Ops: 60/min (nur Writes)  │
│   - Login: 5 Fails/15min je (IP+Konto) + 30/15min/IP Backstop        │
│   - File Uploads: 200/hour/IP (FILE_UPLOAD_RATE_LIMIT)               │
│   - Email Inbound: 60/min global, 30/hour/sender                     │
│ • Input Validation (Zod schemas)                                     │
│ • SQL Injection Protection (Prisma ORM)                              │
│ • XSS Protection (DOMPurify client-side)                             │
│ • API-Keys (INTERNAL_API_KEY for worker auth)                        │
└──────────────────────────────────────────────────────────────────────┘

Layer 7: AUTHENTICATION & AUTHORIZATION
┌──────────────────────────────────────────────────────────────────────┐
│ • JWT Tokens (HttpOnly Cookies)                                      │
│ • Password Hashing (PBKDF2-SHA512, 210k iterations — FIPS 140-2)     │
│ • Multi-Factor Authentication (native TOTP + Entra ID MFA)           │
│ • Entra ID SSO (Azure AD, OAuth 2.0)                                 │
│ • API-Keys (for external integrations)                               │
│ • Token Refresh (refresh_token flow)                                 │
│ • Session Management (Redis-backed, configurable expiry)             │
│ • Cloudflare Turnstile CAPTCHA (Bot Protection)                      │
└──────────────────────────────────────────────────────────────────────┘

Layer 8: COMPLIANCE & AUDIT
┌──────────────────────────────────────────────────────────────────────┐
│ • SHA-256 Hash-Chain (tamper-evident, immutable)                     │
│ • Immutability (DB trigger prevents UPDATE/DELETE)                   │
│ • 9 Audit-Domains (AUTH, ENTITY, ADMIN, SECURITY, SLA, etc.)         │
│ • Chain-Verification-API (Quick-Check & Full-Verification)           │
│ • FIPS 140-2 compatible algorithms (Standard + FIPS Mode)            │
│ • Supports ISO 27001, SOC 2 and GDPR audits                          │
│ • Retention-Policies (7+ years for Audit-Logs)                       │
└──────────────────────────────────────────────────────────────────────┘

1. Transport Security (Traefik API-Gateway)

TLS/SSL Configuration

Transport Security wird durch Traefik v3 als zentrales API-Gateway bereitgestellt. Traefik terminiert TLS, setzt Security-Headers und erzwingt Rate-Limits bevor Requests das Backend erreichen.

Feature Konfiguration Details
TLS-Versionen TLS 1.2, TLS 1.3 Blockiert: SSLv3, TLS 1.0, TLS 1.1 (Traefik minVersion: VersionTLS12)
Cipher-Suites ECDHE-RSA/ECDSA-AES-GCM, ChaCha20-Poly1305 Perfect Forward Secrecy, 6 explizite Cipher-Suites
HSTS max-age=31536000; includeSubDomains; preload 1 Jahr, alle Subdomains, Preload-fähig
HTTP Redirect 301 Permanent Redirect Erzwingt HTTPS (Traefik entrypoint redirect)
Rate-Limiting 100 req/s, burst 200 DDoS-Schutz auf Gateway-Ebene (Traefik middleware)
Sperre interner Schnittstellen Priority-Router → noop@internal Interne Schnittstellen zwischen den Diensten sind von außen nicht erreichbar (Traefik sperrt sie)

Externer Reverse Proxy: Wenn Eviworx hinter einem externen Reverse Proxy (z.B. Nginx, HAProxy) betrieben wird, müssen TRUSTED_PROXIES (.env) und forwardedHeaders.trustedIPs (traefik/traefik.yml) konfiguriert werden, damit Client-IPs korrekt geloggt werden und Rate-Limiting auf die echte Client-IP greift. Installation → Externer Reverse Proxy

📘 Details: Siehe Container Architecture → (Traefik Container)

Traefik Routing & Prioritäten

Router Rule Priority Middlewares
block-internal-apiPathPrefix(/api/internal)40security-headers
backend-apiPathPrefix(/api)30security-headers, compress, rate-limit
backend-wsPathPrefix(/socket.io)20security-headers
frontend-spaPathPrefix(/)10security-headers, compress, rate-limit

2. Application Security

Role-Based Access Control (RBAC)

  • 28+ Permission-Module: tickets, problems, changes, incidents, assets, contracts, licenses, workflows, cronjobs, users, settings, audit, etc.
  • 200+ Individual Permissions: viewAll, viewOwn, create, editStatus, assign, approve, delete
  • Rechte-Cache: pro Rolle 5 min für lesende Anfragen; ändernde Anfragen und kritische Aktionen lesen die Rechte immer frisch aus der Datenbank
  • Keine Rechte im Token: Die Rechte werden bei jeder Anfrage anhand der Rolle geladen; ein älteres Token verschafft keine inzwischen entzogenen Rechte
  • 4 System-Roles: END_USER, AGENT, ADMIN, APPROVER (nicht löschbar, nicht deaktivierbar)
  • Unified Actor: User (Cookie) und API-Key (X-API-Key mit Rolle) durchlaufen dieselbe Rechteprüfung gegen die Matrix ihrer Rolle

📘 Details: Siehe Permissions & RBAC →, User Management → und Users & Roles API →

Security Headers (via Traefik)

Alle Security-Headers werden zentral durch die Traefik security-headers Middleware gesetzt:

Header Wert Zweck
Content-Security-Policy default-src 'self'; script-src 'self' https://challenges.cloudflare.com XSS-Protection (Turnstile CAPTCHA erlaubt)
X-Frame-Options SAMEORIGIN Clickjacking-Protection
X-Content-Type-Options nosniff MIME-Sniffing verhindern
X-XSS-Protection 1; mode=block XSS-Filter aktivieren
Referrer-Policy strict-origin-when-cross-origin Referrer-Leak verhindern
Permissions-Policy geolocation=(self), microphone=(), camera=(self) Browser-Permissions einschränken
Strict-Transport-Security max-age=31536000; includeSubDomains; preload HTTPS erzwingen (1 Jahr)

3. Data Security

SHA-256 Audit-Chain

  • Immutable Logs: UPDATE/DELETE verboten (DB-Trigger)
  • Hash-Chain: Jedes Event verlinkt zum vorherigen via SHA-256
  • Chain-Verification: API-Endpoint prüft Integrität der gesamten Kette
  • PII-Scrubbing: Automatisch Passwords, Tokens, Email, Phone redacted
  • Multi-Org Isolation: Separate Chains pro Organisation
  • Redis-Fallback: Bei DB-Fehler → Redis-Backup (7 Tage TTL)

📘 Details: Siehe Enterprise Audit System →

Encryption at Rest

Daten-Type Verschlüsselung Key-Management
License-Keys AES-256-GCM LICENSE_ENCRYPTION_KEY (env)
Passwords PBKDF2-SHA512 (210k iterations) One-way Hash (FIPS 140-2)
TOTP-Secrets AES-256-GCM TWO_FACTOR_ENCRYPTION_KEY (env)
Mailbox-Credentials (SMTP/IMAP) AES-256-GCM MAILBOX_ENCRYPTION_KEY (env)
Globale Credentials: SMTP-Passwort, MS-Graph & Entra-ID clientSecret, Notification-Adapter (Webex botToken, Teams appPassword) AES-256-GCM MAILBOX_ENCRYPTION_KEY (env)
JWT Tokens HMAC-SHA256 (HS256) JWT_SECRET (env)

Alle globalen Credentials werden beim Speichern mit AES-256-GCM verschlüsselt (derselbe Schlüssel wie bei den Mailbox-Credentials: MAILBOX_ENCRYPTION_KEY, ersatzweise LICENSE_ENCRYPTION_KEY) und erst beim Gebrauch entschlüsselt. Lässt sich ein gespeicherter Wert nicht entschlüsseln, bricht die Funktion mit einer Fehlermeldung ab; die Credentials müssen dann neu eingegeben werden.

📘 Details: Siehe Contracts & Licenses API → (License-Key Encryption)

Optimistic Locking

  • Incidents: Version-Field verhindert Concurrent-Modifications
  • Problems: Version-Field für Conflict-Detection
  • Assets: Version-Field bei Updates
  • Contracts: Version-Field bei Financial-Updates
  • Conflict-Response: 409 CONFLICT mit aktuellem Entity-State

4. Container Security

Zero-Trust Architecture (av-worker)

# av-worker: MAXIMUM HARDENING
read_only: true                    # Filesystem fully read-only
tmpfs:
  - /app/tmp:size=64M,mode=1777    # In-memory temporary storage
  - /tmp:size=64M,mode=1777
security_opt:
  - no-new-privileges:true         # Prevents privilege escalation
cap_drop:
  - ALL                             # All capabilities dropped!

# AV-Worker has NO access to the uploads volume
# Communicates only via:
# 1. ClamAV TCP API (Port 3310)
# 2. Backend HTTP API (Status-Updates)

🔒 Zero-Trust: Der av-worker ist der am stärksten gehärtete Container. Siehe Container Architecture → und Attachments API →

Traefik Container Security

# Traefik: API gateway hardening
security_opt:
  - no-new-privileges:true         # Prevents privilege escalation
volumes:
  - ./traefik/traefik.yml:/etc/traefik/traefik.yml:ro    # Read-only config
  - ./traefik/dynamic.yml:/etc/traefik/dynamic.yml:ro    # Read-only routing
  - ./certs/cert.pem:/etc/traefik/ssl/cert.pem:ro     # Read-only cert
  - ./certs/cert.key:/etc/traefik/ssl/cert.key:ro     # Read-only key

Redis Password Authentication

Redis ist passwort-geschützt. Alle Services verbinden sich mit authentifizierter URL:

# Redis: password-protected
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
# All services connect via:
# redis://:${REDIS_PASSWORD}@redis:6379

Least-Privilege Database-Access

DB-User Berechtigungen Verwendet von
helpdesk_user Full Access (alle Tabellen) Backend (Migrations)
helpdesk_jobworker Restricted: CronJob, JobExecution, WorkerInstance Job-Worker
helpdesk_readonly SELECT-only (alle Tabellen) Analytics, Reporting

📘 Details: Siehe Container Architecture → (PostgreSQL Container)

Container-Hardening Summary

Container Read-Only Non-Root Cap-Drop no-new-priv Resources Härtungsgrad
AV-Worker✅ ALL1.5G / 1C⭐⭐⭐⭐⭐
Email-Worker✅ ALL512M / 1C⭐⭐⭐⭐⭐
Job-Worker✅ ALL1G / 1C⭐⭐⭐⭐⭐
Notification-Worker✅ ALL512M / 1C⭐⭐⭐⭐⭐
Workflow-Engine✅ ALL512M / 1C⭐⭐⭐⭐⭐
Report-Generator✅ ALL1.5G / 1C⭐⭐⭐⭐⭐
Frontend✅ 3 caps256M / 0.5C⭐⭐⭐⭐
TraefikPartial (ro)256M / 1C⭐⭐⭐⭐
ClamAV✅ 3 caps2G / 2C⭐⭐⭐⭐
Backend✅ 3 caps2G / 2C⭐⭐⭐
PostgreSQL✅ 2 caps2G / 2C⭐⭐⭐
Redis✅ 2 caps1G / 1C⭐⭐⭐

Cap-Drop "ALL" = alle Linux-Capabilities entfernt. "3 caps" = NET_RAW, SYS_ADMIN, MKNOD. "2 caps" = NET_RAW, SYS_ADMIN. Resources = Memory-Limit / CPU-Limit. Alle Container haben JSON-Logging mit Rotation (10MB x 3).

5. File Security

Zero-Trust Virus-Scan Flow

ZERO-TRUST VIRUS-SCAN (7 SCHRITTE):

1. User uploads file
   POST /api/attachments/TICKET/:id
   ↓
2. Backend receives file
   • Stores in uploads/ volume
   • Creates Attachment record (scanStatus: PENDING)
   • NO direct ClamAV scan (zero-trust!)
   ↓
3. AV-Worker polls (every 10 seconds, SCAN_POLL_CRON)
   • Backend returns list of PENDING attachments
   ↓
4. AV-Worker initiates scan
   • TCP 3310 to ClamAV
   • Sends file PATH (not content!)
   • ClamAV reads from uploads/ volume (read-only)
   ↓
5. ClamAV scans file
   • Returns: CLEAN / INFECTED / ERROR
   ↓
6. AV-Worker updates Backend
   • Reports scan result (e.g. CLEAN)
   ↓
7. Backend updates Attachment
   • scanStatus: PENDING → CLEAN
   • If INFECTED:
     - Move to quarantine/ volume
     - Notify admin
     - Block download

SICHERHEITS-FEATURES:
✅ av-worker has NO file access (read-only filesystem, no uploads mount)
✅ ClamAV has a read-only mount on uploads/
✅ Backend has read-write, but no scan access
✅ Quarantine volume isolates infected files

📘 Details: Siehe Attachments API → (Zero-Trust Virus-Scan Section)

File-Upload Security

  • Extension-Blacklist: .exe, .bat, .sh, .dll, .js, .vbs, .msi, .com, .cmd, .scr blockiert
  • MIME-Type Validation: Server-side (nicht nur Extension)
  • File-Size-Limits: Global 100MB, per-Entity konfigurierbar
  • Upload Rate-Limit: FILE_UPLOAD_RATE_LIMIT: 200/hour/IP (konfigurierbar)
  • Max-Files-Limit: Pro Entity (z.B. max 10 Attachments pro Ticket)
  • Retention-Policy: Auto-Delete nach X Tagen (konfigurierbar)
  • Orphan-Cleanup: Ungenutzte Files nach 24h löschen
  • Soft-Delete: Recovery-Window (Files bleiben X Tage nach Delete)

6. API Security

SSRF Protection

Webhook-URLs und externe API-Calls werden validiert, um SSRF-Angriffe zu verhindern. Dieselbe Prüfung greift beim Speichern und bei der Ausführung (Job-Worker, Workflow-Engine). Ungültige Einträge in der Allowlist werden ignoriert und geben nichts frei.

  • Erlaubte Schemes: HTTP und HTTPS (kein HTTPS-Zwang), beschränkt auf erlaubte Ports — Default 80, 443, 8080, 8443, anpassbar via SSRF_ALLOWED_PORTS
  • Hart geblockt (NIE per Allowlist freigebbar): localhost, 127.0.0.1, ::1, 0.0.0.0, Cloud-Metadata (169.254.169.254, metadata.google.internal, metadata.azure.com), Link-Local (fe80::), Multicast (ff00::)
  • Per Default geblockt, aber via SSRF_ALLOWLIST freigebbar: private Netze (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, IPv6 ULA fc00::/fd00::) — z.B. für interne ERP-/Monitoring-Webhooks (IP/CIDR/Hostname, keine Ports)
  • Teams-URLs: Nur Microsoft-Domains erlaubt (outlook.office.com, outlook.office365.com, webhook.office.com)

📘 Details: Siehe Workflows API →, CronJobs API →, Integrations →

Rate-Limiting

Endpoint/Feature Limit Zeitfenster Typ
Traefik Gateway100 req/s, burst 200Pro SekundeGlobal (DDoS-Schutz)
File-Uploads200Pro StundePer IP
E-Mail Inbound (Global)60Pro MinuteGlobal
E-Mail Inbound (Sender)30Pro StundePer Sender
E-Mail Max-Größe25 MB-Pro E-Mail

Umsetzung: Traefik-Rate-Limit (Gateway-Ebene) plus Limits im Backend (Anwendungsebene)

📘 Details: Siehe Integrations → (E-Mail Rate-Limiting)

Input Validation

  • Zod Schemas: Alle API-Inputs werden validiert (Type-Safe)
  • SQL Injection: Prisma ORM verhindert SQL-Injection (Prepared Statements)
  • XSS Protection: DOMPurify client-side, CSP Headers server-side (Traefik)
  • Path-Traversal: File-Paths validiert, keine ../ erlaubt

7. Authentication & Authorization

Authentication-Methoden

Methode Beschreibung Use-Case
JWT (HttpOnly Cookies) Standard Web-Login Portal-User (Agents, Customers)
Entra ID SSO Azure AD OAuth 2.0 Enterprise Single-Sign-On
Native TOTP MFA HMAC-SHA256 TOTP (FIPS-kompatibel) Alle User (Security-Einstellungen)
Cloudflare Turnstile CAPTCHA Bot-Protection Login/Registrierung
API-Keys Header X-API-Key für externe Systeme Workflow-API-Trigger, Integrationen
INTERNAL_API_KEY Gemeinsamer Schlüssel, mit dem sich die Worker beim Backend authentifizieren Inter-Container-Communication

📘 Details: Siehe Authentication API →

FIPS 140-2 kompatible Kryptografie

Das Backend verwendet ausschließlich FIPS 140-2 kompatible Algorithmen. Hinweis: Es handelt sich um die Nutzung FIPS-kompatibler Algorithmen, nicht um eine offizielle FIPS-Zertifizierung. Es gibt zwei Betriebsmodi:

Komponente Algorithmus Details
Passwort-Hashing PBKDF2-SHA512 210,000 Iterationen, 64-Byte Key, 32-Byte Salt
2FA (TOTP) HMAC-SHA256 Nicht SHA-1 (FIPS-kompatibel)
Verschlüsselung AES-256-GCM License-Keys, TOTP-Secrets und gespeicherte Credentials
JWT Signing HS256 HMAC-SHA256

Betriebsmodi

Modus FIPS-kompatible Algorithmen FIPS-Modus erzwungen Docker Image
Standard node:24-slim
Strict FIPS Distroless FIPS-Base-Image (Node.js 24, OpenSSL 3.0 FIPS Provider)

Im Strict-FIPS-Modus läuft Node.js mit --enable-fips und OpenSSL 3.0 FIPS Provider. MD5, MD4, RIPEMD160 werden blockiert. Der Startup-Check (ENABLE_FIPS=true) stoppt den Server sofort wenn crypto.getFips() !== 1.

FIPS-Konfiguration

Variable Default Beschreibung
DOCKERFILE_BACKENDDockerfileDockerfile.fips für den Strict-FIPS-Modus
ENABLE_FIPSfalseStartup-Check: Server stoppt wenn FIPS nicht aktiv
PBKDF2_ITERATIONS210000PBKDF2-Iterationen (Bereich: 100k–2M)
UV_THREADPOOL_SIZE16libuv Thread Pool für async PBKDF2

Password-Hashing Sicherheitsmechanismen

  • Verify-Whitelisting: Nur sha512, Keylen 64, Iterationen 100k–2M akzeptiert
  • Timing-Safe: crypto.timingSafeEqual für Passwort-Vergleiche
  • Gleiche Antwortzeit: Auch für unbekannte Konten wird ein Hash berechnet; die Antwortzeit verrät also nicht, ob ein Konto existiert
  • Automatisches Rehash: Hashes mit niedrigerer Iterationszahl als konfiguriert werden beim nächsten erfolgreichen Login neu berechnet
  • Hash-Format: pbkdf2:sha512:<iterations>:<keylen>:<salt_base64>:<hash_base64>
  • Base64-Validierung: Strikte Prüfung von Salt und Hash-Buffers

Native MFA/TOTP

Zusätzlich zu Entra ID MFA bietet das System native TOTP-basierte Multi-Faktor-Authentifizierung:

  • Algorithmus: HMAC-SHA256 (FIPS-kompatibel, nicht SHA-1)
  • Secret-Verschlüsselung: AES-256-GCM via TWO_FACTOR_ENCRYPTION_KEY
  • Aktivierung: User Security-Einstellungen (self-service)
  • Key-Trennung: TWO_FACTOR_ENCRYPTION_KEY ist separat von JWT_SECRET

Cloudflare Turnstile CAPTCHA

  • Schutz: Bot-Protection für Login und Registrierung
  • CSP-Integration: challenges.cloudflare.com in script-src, connect-src, frame-src erlaubt
  • Konfiguration: TURNSTILE_SITE_KEY, TURNSTILE_SECRET_KEY (env)

JWT Token Security

  • HttpOnly Cookies: JavaScript kann Token nicht lesen (XSS-Protection)
  • Secure Flag: Cookie nur über HTTPS übertragen
  • SameSite: CSRF-Protection
  • Token-Rotation: JWT_SECRET_OLD unterstützt graduelle Key-Rotation
  • Keine Rechte im Token: Die Rechte werden bei jeder Anfrage anhand der Rolle geladen (verhindert Rechteausweitung über veraltete Tokens)
  • Expiration: Tokens laufen ab (konfigurierbar)

Session Security

Variable Default Beschreibung
SESSION_MAX_HOURS12Hartes Session-Ende in Stunden (backend-enforced, per Refresh nicht verlängerbar)
ACCESS_TOKEN_EXPIRY_MINUTES60Access-Token Ablaufzeit in Minuten
REFRESH_TOKEN_EXPIRY_MINUTES100Refresh-Token Ablaufzeit in Minuten (bewusst knapp — s. Rotation unten)
IDLE_TIMEOUT_MINUTES30Auto-Logout bei Inaktivität (Server-Wert, im Client durchgesetzt)
COOKIE_SECURE(NODE_ENV)Secure-Flag der Auth-Cookies explizit erzwingen/abschalten
JWT_SECRET_OLD-Vorheriger JWT-Secret für graduelle Key-Rotation

Refresh-Token-Rotation & Diebstahl-Erkennung

  • Rotation bei jedem Refresh: Ein Refresh-Token ist ein Einmal-Ticket — nach Einlösung wird er ersetzt.
  • Grace-Fenster (60 Sek.): Geht die Antwort verloren (Timeout/Abbruch), darf der alte Token kurz erneut eingelöst werden — die Session strandet nicht wegen eines Netzwerkfehlers.
  • Reuse-Erkennung (10 Min.): Taucht ein längst ersetzter Token danach wieder auf, gilt er als entwendet: die gesamte Session wird sofort beendet, WebSockets getrennt, Audit-Eintrag REFRESH_TOKEN_REUSE.
  • Sofortiger Revoke: Session-Beendigung (Sessions-UI, Passwortwechsel, Reuse) wirkt sofort über die stabile Session-ID — unabhängig davon, wie oft der Token seither rotiert wurde.
  • Im Zweifel gesperrt: Ist Redis für Blacklist-/Revoke-Prüfung nicht erreichbar, wird der Zugriff verweigert (503) statt im Zweifel gewährt.
  • Beendet bleibt beendet: Wurde eine Session beendet, stellt kein Pfad je wieder Tokens für sie aus — auch nicht das Grace-Fenster der Rotation.

Brute-Force-Schutz & Rate-Limiting

Der Schutz sitzt am ZIEL-Objekt, nicht an der IP. Das ist die wichtigste Designentscheidung dieses Bereichs — denn hinter einem Firmen-NAT teilen sich alle Mitarbeitenden eine einzige IP. Ein IP-Limit, das eng genug wäre, um einen Angreifer aufzuhalten, würde dort zuerst das eigene Büro aussperren.

Ebene Schutz
1. Am Objekt (die echte Bremse) Konto-Sperre pro E-Mail mit exponentieller Verzögerung (5 Fehlversuche → bis zu 4 h), CAPTCHA ab dem 3. Fehlversuch, 2FA-Versuchslimit pro Benutzer, Passwort-Reset 1 Anfrage / 2 min pro E-Mail. Diese Grenzen greifen unabhängig davon, von wie vielen IPs ein Angreifer kommt.
2. An der IP (Flood-Backstop) Login zählt je Kombination aus IP UND Konto (5/15 min) — ein Kollege mit Tippfehler sperrt nur sich selbst; dazu ein IP-Deckel über alle Konten (30/15 min) gegen das Durchprobieren vieler Adressen. Refresh (60), Logout (120), 2FA/Reset (20), Einladungs-Prüfung (30) und der globale Deckel (2000/min) sind bewusst großzügig: Sie sollen Fluten bremsen, nicht Passwörter raten — dafür sind Refresh-/Reset-Tokens mit 64 Zeichen ohnehin nicht erratbar.

Warum der Login-Zähler auf (IP + Konto) läuft und nicht auf der E-Mail allein: Ein reiner E-Mail-Zähler ließe sich missbrauchen, um fremde Konten gezielt auszusperren — man müsste nur oft genug ein falsches Passwort schicken. Die Paarung verhindert das.

Wer gegen eine laufende Konto-Sperre anläuft, bekommt dieselbe Antwort wie an jeder anderen Bremse: 429 mit dem Hinweis auf zu viele Fehlversuche. Ein CAPTCHA wird dabei nicht verlangt — es würde an einer laufenden Sperre nichts ändern. Die Meldung sagt damit, was wirklich vorliegt: ein Zustand auf Zeit, kein gesperrtes Konto.

Zwei Betriebshinweise: Die IP-Zähler der Ebene 2 liegen im Speicher der Backend-Instanz; ein Neustart setzt sie zurück. Die Konto-Sperren der Ebene 1 liegen in Redis und bleiben dabei erhalten. Und hinter einem externen Reverse-Proxy muss TRUSTED_PROXIES stimmen — sonst sehen alle Requests wie eine IP aus und jedes IP-Limit trifft sofort alle. Alle Werte sind ENV-bar und ohne Rebuild anhebbar: Environment → Rate-Limits.

Echtzeit-Kanäle prüfen dieselbe Sichtbarkeit

Die Anwendung hält Detailseiten live: wer ein Objekt geöffnet hat, sieht die Betrachter neben sich und bekommt Änderungen ohne Neuladen. Er prüft dieselbe Zeilen-Sicht wie der REST-Endpunkt, die Liste und die globale Suche, aus derselben Quelle.

  • Zwei Ebenen, beide geprüft: der Listen-Kanal eines Typs verlangt das Leserecht dieses Typs, der Kanal eines einzelnen Objekts zusätzlich die Sicht auf genau diese Zeile — einschließlich Asset-Typ-Sperren, Mailbox- und Gruppen-Einschränkungen sowie der Freigaben eines Wissensartikels.
  • Kein Raten über IDs: Wer für ein Objekt keine Sicht hat, bekommt beim Betreten eine Ablehnung statt einer Betrachter-Liste, und ein Sammel-Abonnement filtert solche Objekte still heraus. Unbekannte Typen werden abgelehnt, und die Zahl der Objekte je Abonnement ist gedeckelt.
  • Folge für eingeschränkte Zeilen: Eine Verknüpfung, die nur als Platzhalter sichtbar ist, aktualisiert sich nicht live. Das ist gewollt: Der Platzhalter verrät nichts über den Inhalt, und der Live-Kanal ebenso wenig.

Wie der Kanal arbeitet, was Anwender davon sehen und welche Objektarten er abdeckt: Echtzeit & Presence →

8. Compliance & Audit

Enterprise Audit System

  • SHA-256 Hash-Chain: Jeder Eintrag ist per SHA-256 mit dem vorherigen verkettet; Manipulationen werden bei der Prüfung erkannt
  • Immutability: UPDATE/DELETE verboten (DB-Trigger)
  • PII-Scrubbing: Automatisch Passwords, Tokens, Email, Phone redacted
  • 9 Audit-Domains: AUTH, ENTITY, ADMIN, SECURITY, SLA, WORKFLOW, SYSTEM, DATA_ACCESS, NOTIFICATION
  • 5 Severity-Levels: DEBUG, INFO, WARNING, ERROR, CRITICAL
  • Redis-Fallback: Bei DB-Fehler → Redis-Backup (7 Tage TTL)
  • Chain-Verification-API: Quick-Check & Full-Verification

📘 Details: Siehe Enterprise Audit System →

Unterstützte Standards

Standard Unterstützte Anforderungen
FIPS 140-2 PBKDF2-SHA512, HMAC-SHA256, AES-256-GCM, Strict-FIPS-Modus verfügbar
ISO 27001 Audit-Logging, Access-Control, Encryption, Incident-Management
SOC 2 Audit-Trail, Change-Management, Monitoring, Security-Controls
GDPR PII-Scrubbing, Data-Retention, User-Anonymisierung, Audit-Logs
NIS2 Incident-Reporting, SLA-Tracking, Security-Monitoring

Security Best Practices

Secrets-Management

  1. Alle Secrets ändern: JWT_SECRET, POSTGRES_PASSWORD, INTERNAL_API_KEY, LICENSE_ENCRYPTION_KEY, TWO_FACTOR_ENCRYPTION_KEY, REDIS_PASSWORD
  2. Docker Secrets: Verwende Docker Secrets (Swarm) oder Kubernetes Secrets statt ENV
  3. Key-Rotation: JWT_SECRET_OLD ermöglicht graduelle Rotation
  4. LICENSE_ENCRYPTION_KEY: NIEMALS ändern nach ersten Lizenzen (Daten-Verlust!)
  5. TWO_FACTOR_ENCRYPTION_KEY: NIEMALS ändern nach erster MFA-Aktivierung (TOTP-Secrets unlesbar!)
  6. Generation: openssl rand -hex 32 für sichere Keys

📘 Details: Siehe Environment Variables → (Secret-Generation)

Role-Based Access Control (RBAC)

  1. Least-Privilege: Nutze viewOwn für END_USER, viewAll nur für AGENT/ADMIN
  2. Custom-Roles: Erstelle Custom-Roles nur bei Bedarf (komplexer zu managen)
  3. Permission-Audit: Role-Changes werden geloggt (ADMIN Domain, WARNING Severity)
  4. Critical-Actions: tickets.delete, changes.approve immer DB-Revalidation (kein Cache)
  5. Permission-Cache: 5min TTL, invalidiert bei Role-Change

Password-Policy

  • PBKDF2-SHA512: 210.000 Iterationen (FIPS 140-2 kompatibel, konfigurierbar via PBKDF2_ITERATIONS)
  • One-Way-Hash: Passwords können nicht dekodiert werden
  • Password-Reset: Secure-Token via E-Mail (zeitlich begrenzt)
  • Empfehlung: Min. 12 Zeichen, Sonderzeichen, Zahlen

Security-Features nach Feature-Bereich

ITSM-Core (Tickets, Incidents, Problems, Changes)

  • Permission-basierte Visibility: User sehen nur erlaubte Entities
  • Internal Notes: Nur sichtbar mit viewInternal-Permission
  • Optimistic Locking: Version-Field verhindert Race-Conditions
  • Self-Approval Block: Requester ≠ Approver (Changes, Incidents)
  • Activity-Timeline: Vollständige Audit-Trail aller Änderungen

Assets & Inventory

  • QR-Code Handover: HMAC-Token für Public-Endpoint (zeitlich begrenzt)
  • Type-basierte Permissions: 6 Permissions pro Asset-Type
  • Financial-Data: Separate Permission für Financial-Fields
  • Checkout-Tracking: Wer hat welches Asset wann (vollständiger Verlauf)

📘 Details: Siehe Assets API → (HMAC-Token, Type-Permissions)

Contracts & Licenses

  • AES-256-GCM Encryption: License-Keys encrypted at-rest
  • Format: iv:authTag:encrypted (Base64)
  • Key-Zugriff Audit: Jeder Decrypt wird geloggt (IP, UserAgent, Timestamp)
  • viewSensitive Permission: Benötigt für License-Key-Zugriff

📘 Details: Siehe Contracts & Licenses API → (AES-256-GCM Encryption)

Workflows & Automation

  • SSRF Protection: Webhook-Actions validiert (private IPs nur via SSRF_ALLOWLIST, Loopback/Metadata immer geblockt)
  • Circuit-Breaker: Schutz vor Cascade-Failures (Threshold: 5, Reset: 30s)
  • Timeout-Protection: Webhook-Calls max. 30s
  • API-Key-Auth: Workflow-API-Trigger benötigen API-Key

📘 Details: Siehe Workflows API → (SSRF-Protection, Circuit-Breaker)

Security-Incident-Response

Detection-Mechanismen

  • Virus-Detection: ClamAV scannt ALLE Uploads (keine Ausnahmen)
  • Intrusion-Detection: Audit-Events (SECURITY Domain) für verdächtige Aktivitäten
  • Failed-Login-Tracking: Audit-Events (AUTH Domain) für Brute-Force-Detection
  • Permission-Violations: Audit-Events (SECURITY Domain, ERROR Severity)

Response-Aktionen

  • Infizierte Files: Automatisch in Quarantine-Volume verschoben
  • Admin-Notification: Multi-Channel Alert bei Security-Events
  • User-Deactivation: isActive = false (Soft-Delete, reversibel)
  • Permission-Revocation: Rollen-Änderungen wirken sofort (der Rechte-Cache der Rolle wird dabei geleert)
  • Audit-Investigation: Chain-Verification-API für Forensik

Security-Checkliste (Production)

Vor Production-Start

⚠️ KRITISCH - MUSS geändert werden:

  • ☐ JWT_SECRET ändern (nicht default verwenden!)
  • ☐ POSTGRES_PASSWORD ändern (supersecretpassword → secure)
  • ☐ JOBWORKER_DB_PASSWORD ändern
  • ☐ READONLY_DB_PASSWORD ändern
  • ☐ INTERNAL_API_KEY ändern (openssl rand -hex 32)
  • ☐ LICENSE_ENCRYPTION_KEY ändern (NIEMALS später ändern!)
  • ☐ TWO_FACTOR_ENCRYPTION_KEY ändern (NIEMALS später ändern!)
  • ☐ REDIS_PASSWORD ändern (openssl rand -hex 32)
  • ☐ TURNSTILE_SITE_KEY + TURNSTILE_SECRET_KEY konfigurieren (Cloudflare Dashboard)
  • ☐ VAPID_KEYS neu generieren (Web-Push)

Nach Production-Start

  • ☐ Admin-Passwort ändern (admin@company.com) und MFA aktivieren
  • ☐ SEED_DATABASE=false setzen (keine neuen Test-User)
  • ☐ TLS-Zertifikate von Let's Encrypt (nicht self-signed)
  • ☐ Firewall-Rules (nur 80, 443 public)
  • ☐ Health-Checks überwachen
  • ☐ Backup-Strategy testen (postgres_data, uploads)
  • ☐ Audit-Logs regelmäßig prüfen (Chain-Verification)
  • ☐ ClamAV Virus-Defs aktualisiert (Freshclam)
  • ☐ FIPS-Modus erwägen für regulierte Umgebungen (DOCKERFILE_BACKEND=Dockerfile.fips)

Verwandte Dokumentation