Skip to content

v0.1.35 — security hardening + performance

Choose a tag to compare

@invizen invizen released this 08 Oct 05:12

Security hardening (external review batch)

A round of independent review surfaced six issues; all are fixed here.

  • Session tokens now actually expire. ValidSession returned the map-hit
    instead of the expiry result, so an expired token was admitted one last time
    (and the UI's 5s poll kept sliding live sessions' own expiry). Expired tokens
    are now rejected and deleted in one pass.
  • Stored XSS via sensor name closed (two layers). A crafted sensor name
    could escape its string context in inline event handlers. The UI now escapes
    at the JS level for every onclick sink, and the API rejects names
    containing quotes/angle brackets/backticks/backslashes/control chars or over
    60 characters on create and rename (400).
  • Login: per-IP failure throttle + timing-oracle close. 7 failed logins
    from one IP in 60s → 5-minute lockout (429 + Retry-After), enforced before
    any bcrypt work; a success clears the counter. The unknown-user dummy hash's
    cost is now derived from the configured bcrypt cost so it can't drift, and
    every rejected login pays a constant 200ms slowdown — capping online
    password guessing at ~5 tries/second/IP. No per-account lockout: a typo'd
    password can never lock the operator out.
  • All request bodies bounded to 1 MiB. The auth gate now wraps every
    request body with http.MaxBytesReader; oversized bodies get a clean 413
    instead of being streamed into the JSON decoder.
  • GET /api/events?n= capped at 500, matching the sensor-history endpoint
    (previously unbounded).
  • POST /api/settings/test rejects unknown/missing provider kinds with 400
    naming the valid kinds, instead of answering 200 {"ok":false}.

Performance

  • Enabled() no longer hits the database on every request. The "is auth
    enabled" check ran SELECT COUNT(*) FROM users on every request, including
    the dashboard's 5s poll. It's now memoized for 2s; in-app user changes
    (add/remove/disable) refresh it immediately, so the dashboard is never stale
    and out-of-band CLI user management is picked up within 2s.

Polish

  • The sensor form's Timeout field now explains that the pre-resolve DNS
    lookup has its own 5s cap, so timeouts under ~6s don't bound DNS.
  • Corrupt sensor rows (which shouldn't happen with the app-controlled schema)
    are now logged instead of silently vanishing from the fleet view.
  • RemoveAllUsers naming, and tsNow() used at every writer-side timestamp
    site.

Full test suite passes under -race.