Skip to main content

Security Hardening

Stratora ships with security defaults appropriate for internal network monitoring deployments. This page documents the hardening measures in place and configuration options for environments with stricter requirements.


Authentication

Rate Limiting

All authentication endpoints are rate-limited per client IP to prevent brute force and credential stuffing attacks:

EndpointLimitWindow
POST /api/v1/auth/login5 requests5 minutes
POST /api/v1/auth/change-password10 requests1 minute
GET /api/v1/auth/oidc/authorize/:id10 requests1 minute
GET /api/v1/auth/oidc/callback10 requests1 minute
GET /api/v1/auth/sso10 requests1 minute

When a limit is exceeded, the server returns 429 Too Many Requests with a Retry-After header indicating how long to wait.

Session Cookies

Session cookies are set with the following attributes:

  • Secure — cookie only sent over HTTPS
  • HttpOnly — not accessible to JavaScript
  • SameSite=Strict — not sent on cross-origin requests (CSRF protection)
note

In development environments using plain HTTP, the Secure flag means the session cookie won't be sent. The SPA uses Bearer token authentication from localStorage, so login and API calls still work. The cookie is a secondary authentication path used by the OIDC callback flow.

OIDC Token Delivery

After OIDC authentication, the session token is delivered to the frontend via a URL fragment (#oidc_session=...), not a query parameter. Fragments are never sent to the server, keeping the token out of server logs, proxy logs, and HTTP Referer headers.


HTTP Security Headers

NGINX Headers

NGINX sets the following headers on all responses:

HeaderValue
X-Frame-OptionsDENY
X-Content-Type-Optionsnosniff
X-XSS-Protection1; mode=block
Referrer-Policystrict-origin-when-cross-origin
Strict-Transport-Securitymax-age=31536000; includeSubDomains
Permissions-Policycamera=(), microphone=(), geolocation=(), payment=(), usb=(), accelerometer=(), gyroscope=()
Content-Security-Policydefault-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src 'self'; img-src 'self' data: blob:; font-src 'self' data:; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; upgrade-insecure-requests;

server_tokens is set to off to suppress the NGINX version in the Server response header.

Go Backend Headers (Defense-in-Depth)

The Go backend also sets security headers on all /api/v1/ responses, providing protection even if the backend is accessed directly (bypassing NGINX):

  • X-Content-Type-Options: nosniff
  • X-Frame-Options: DENY
  • X-XSS-Protection: 1; mode=block
  • Referrer-Policy: strict-origin-when-cross-origin
  • Cache-Control: no-store, private (with Pragma: no-cache)

The Cache-Control: no-store header is applied to all API responses except the collector config endpoint (/remote-collectors/:id/config), which uses ETag-based conditional requests for bandwidth efficiency.


API Key Management

Key Rotation

Component API keys can be rotated from the Settings > Components page. The rotation endpoint (POST /api/v1/remote-components/:id/rotate) generates a new key, invalidates the old one, and returns the new key in a one-time reveal modal.

The component will need to be reconfigured with the new key after rotation. For agents, this means updating /etc/stratora/agent.json (Linux) or the registry key (Windows) and restarting the service.

Key Security

  • Keys are hashed with bcrypt (cost 12) for storage
  • A SHA-256 indexed hash enables O(1) lookup performance
  • Only a prefix (sk_stra_xxxx...) is displayed in the UI — the full key is shown only once at creation or rotation
  • Revoked components cannot authenticate; revocation is immediate

Network Architecture

Port Exposure

PortBindingPurpose
443 (HTTPS)All interfacesNGINX reverse proxy — serves frontend and proxies API
80 (HTTP)All interfacesRedirects to HTTPS; ACME challenge support
80800.0.0.0 (configurable)Go backend API — should not be exposed to external networks
8428127.0.0.1VictoriaMetrics — loopback only
5432127.0.0.1PostgreSQL — loopback only
warning

Port 8080 (the Go backend) binds to all interfaces by default. In production, ensure your firewall blocks external access to port 8080. All client traffic should go through NGINX on port 443.

To restrict the backend to loopback only, set in config.yaml:

server:
host: "127.0.0.1"
port: 8080