Skip to main content

Security model

This page explains how Ticketra's security mechanisms work. For the operational checklist, see the Hardening guide.

Authentication & sessions

  • Login issues a JWT stored in an httpOnly, Secure, SameSite=Strict cookie — JavaScript can't read it, which neutralizes token theft via XSS.
  • Tokens are verified with the algorithm pinned to HS256, closing algorithm-confusion attacks.
  • Every request re-validates the session against the database: it must be un-revoked, unexpired, the user active, and (for tenant users) the tenant active. Disabling a user or revoking sessions takes effect immediately.
  • Failed logins drive tiered account lockout plus per-account and per-IP rate limiting.

CSRF protection

Because authentication uses cookies, mutating requests are protected with a double-submit token: a non-httpOnly csrf_token cookie must match an X-CSRF-Token header, compared in constant time. Bearer-token (non-cookie) requests and the webhook receiver (Basic Auth, server-to-server) are exempt because they aren't subject to CSRF.

Tenant isolation

Tenant scope is resolved server-side and applied to every query. Tenant users are pinned to their own tenant and cannot escape it; system users select a tenant explicitly (header for REST, query param for SSE). See Multi-tenancy.

Input handling

  • All SQL is parameterized — no ORM, no string-built queries with user input.
  • File downloads (attachments, avatars, report logos) are defended against path traversal by stripping to a basename and verifying the resolved path stays inside the allowed directory.
  • LDAP search filters are RFC-4515 escaped before substitution.

Secrets & encryption

  • Secrets are read from Docker secret files, never hardcoded.
  • CTI provider API keys are encrypted at rest with AES-256-GCM, using a key derived via scrypt from the integration_encryption_key secret.

Transport & headers

The frontend Nginx terminates TLS and applies a strong Content-Security-Policy (no inline scripts), HSTS, X-Frame-Options: DENY, a restrictive Permissions-Policy, and hides its version. The API additionally sets Helmet's cross-origin isolation headers and a generic 5xx error body so server internals never leak.

Defense in depth, not magic

No single control is load-bearing. An attacker who slips past one layer (say, finds an XSS vector) still faces httpOnly cookies, CSP, CSRF, tenant scoping, and server-side permission checks. That layering is the point.

A note on login timing

When LDAP is enabled, logins for non-existent users can take longer than for known users (the unknown-user path attempts a directory lookup). Treat this as a username-enumeration consideration: keep the LDAP connect timeout low and rely on the rate limiting and lockout above. This is called out in the Hardening checklist.