Sicherheit
Du sicherst den tibi-server auf vier Ebenen: Tokens, CORS, Ratelimit und Dateipfade plus Prozess-Isolation. Quelle ist der Code (internal/config, internal/ratelimit, internal/suexec, internal/controller/setup.go).
Token-Arten
Abschnitt betitelt „Token-Arten“| Art | Header | Wofür | Scope-Syntax |
|---|---|---|---|
| Server-Admin-Token | X-Admin-Token oder Authorization: Bearer |
Betrieb: Reload, Backup, Snapshots, Shutdown (server.shutdown nur für Stop) |
domain.action, Kurzform (project = project.*), * je Segment |
| Benutzer-JWT | X-Auth-Token |
Anmeldung per /api/v1/login; Lebensdauer via API_ACCESS_TOKEN_LIFETIME (Standard 60m) |
Rollen + Collection-Rechte |
| Personal Access Token (PAT) | X-Auth-Token (tibi_pat_…) |
Dauerhafte Maschinen-Tokens, immer aktiv | gleiche Syntax wie Admin-Tokens; es gilt Token-Recht UND Besitzer-Recht |
| MCP | X-Auth-Token (nur PAT) |
KI-Werkzeugzugriff über /api/v1/mcp |
PAT-Scopes, Admin-Aktionen nur mit mcp.allowAdminActions: true |
Gültige Domänen: user, project (read/create/update/delete, reload, backup, regenerate-search, snapshot), team, org, audit.read, llm.chat, namespace.<ns>.<collection>.<aktion>.
Anfrage-Recht: namespace.shop.artikel.readToken-Scope: namespace.shop → passt (Kurzform)Token-Scope: namespace.*.artikel.read → passt (Wildcard)Besitzer darf es nicht → trotzdem verboten (UND-Regel)CORS-Kaskade
Abschnitt betitelt „CORS-Kaskade“Jeder Request bekommt genau eine CORS-Config — vom Spezifischen zum Allgemeinen:
/_actions/<name> → /<collection> → / → "" → keine (Browser blockt)- Die Kaskade steht pro Projekt (
CORSMap), nicht global. Dercors:-Abschnitt der Server-Config ist die Basis, Projekt- und Collection-Werte mergen feldweise dazu (merge: truehängt an,merge: falseersetzt). Globales CORS ist auskommentiert — ohne Projekt-Kontext greift gar kein CORS. - Action-Endpunkte (
/_actions/…) haben eigene Einträge — prüfe sie separat. - Preflight ohne echte Route antwortet
404(kein offenesOPTIONS-Loch).
Ratelimit (Login)
Abschnitt betitelt „Ratelimit (Login)“Der Login-Limiter bremst Fehlversuche mit exponentiellem Backoff — je IP und je Benutzername:
| Schlüssel | Standard | Env |
|---|---|---|
| Erste Verzögerung | 1s |
RATELIMIT_LOGIN_INITIAL_DELAY |
| Maximale Verzögerung | 60s |
RATELIMIT_LOGIN_MAX_DELAY |
| Zähler-Reset nach Ruhe | 15m |
RATELIMIT_LOGIN_RESET_AFTER |
| Ganz abschalten | an (true) |
RATELIMIT_ENABLED=false (nur Notfall) |
Erfolg setzt beide Zähler zurück. Gebremste Versuche antworten mit 429 plus Retry-After-Header (Sekunden) — warte sie ab statt zu hämmern. Das Limit gilt nur für Login, nicht global.
Pfade und suexec-Isolation
Abschnitt betitelt „Pfade und suexec-Isolation“| Schalter | Wirkung |
|---|---|
security.allowAbsolutePaths (SECURITY_ALLOWABSOLUTEPATHS) |
Absolute Dateipfade erlauben — sonst verboten |
security.allowUpperPaths (SECURITY_ALLOWUPPERPATHS) |
..-Pfade erlauben — sonst verboten |
| suexec (kein Schalter) | Hooks und Jobs laufen unter der Projekt-UID/GID in eigenen Thread-Pools |
Der Starter setzt beide Pfad-Schalter lokal auf "true". In Produktion lässt du sie aus, außer du weißt genau warum.
Checkliste für den Go-Live
Abschnitt betitelt „Checkliste für den Go-Live“jwtSecretgesetzt (lang, zufällig) undsecureCookies: true(HTTPS).- Admin-Tokens minimal vergeben: ein Token, ein Zweck, enge Scopes.
RESPONSE_ERROR_STACKaus — keine Stacktraces an Clients.- Pfad-Schalter aus, außer nötig. Ratelimit an.
sentry.dsngesetzt,/metricsnur intern erreichbar.- CORS je Collection geprüft — keine
*-Origins mit Credentials.
Config-Schlüssel stehen unter Server-Konfiguration. Laufende Kontrolle unter Betrieb und Beobachtung.
Verifiziert am 68b4278 2026-10-15 (tibi-server)