Skip to content

security: add HTTP server timeouts, graceful shutdown, and security headers (#11, #12, #13)#588

Merged
lakhansamani merged 1 commit intomainfrom
security/server-hardening
Apr 7, 2026
Merged

security: add HTTP server timeouts, graceful shutdown, and security headers (#11, #12, #13)#588
lakhansamani merged 1 commit intomainfrom
security/server-hardening

Conversation

@lakhansamani
Copy link
Copy Markdown
Contributor

Summary

Three HTTP-server hardenings:

#11 — No HTTP server timeouts (slowloris)
The main HTTP server used router.Run() which constructs an http.Server with no Read/Write/Idle timeouts. A slow client could hold a connection open indefinitely sending headers one byte at a time.

#12 — No graceful shutdown for the main HTTP server
The metrics server already had a Shutdown call wired to context cancellation but the main HTTP server was killed mid-flight when the process received a signal, dropping in-progress responses.

#13 — Missing security headers
The middleware only set X-Content-Type-Options, X-Frame-Options, Referrer-Policy, X-XSS-Protection. Missing HSTS, CSP, Permissions-Policy. Token responses had no Cache-Control.

Changes

  • Build *http.Server explicitly for both the main HTTP and metrics servers with ReadHeaderTimeout: 10s, ReadTimeout: 30s, WriteTimeout: 60s, IdleTimeout: 120s, MaxHeaderBytes: 1 MiB.
  • Both servers now graceful-shutdown via srv.Shutdown(ctx) with a 30s drain timeout when the process context is cancelled.
  • Security headers middleware adds Permissions-Policy (geolocation/microphone/camera/payment/usb disabled), opt-in HSTS via --enable-hsts, default-on CSP with conservative policy and --disable-csp escape hatch.
  • /oauth/token responses now set Cache-Control: no-store, no-cache, must-revalidate, private and Pragma: no-cache per RFC 6749 §5.1.

Test plan

  • go build ./...
  • TEST_DBS=sqlite go test -run TestSignup ./internal/integration_tests/
  • Manual: SIGTERM drains in-flight requests instead of cutting them
  • Manual: response headers include CSP and Permissions-Policy

…eaders (#11, #12, #13)

#11 — No HTTP server timeouts (slowloris)
The main HTTP server used router.Run() which constructs an http.Server
with no Read/Write/Idle timeouts. A slow client could hold a connection
open indefinitely sending headers one byte at a time.

Fix: build *http.Server explicitly with:
- ReadHeaderTimeout: 10s (the slowloris defence — bounds time to receive
  request headers)
- ReadTimeout: 30s
- WriteTimeout: 60s
- IdleTimeout: 120s
- MaxHeaderBytes: 1 MB
The metrics server gets the same hardening.

#12 — No graceful shutdown for the main HTTP server
The metrics server already had a Shutdown call wired to context cancellation
but the main HTTP server was killed mid-flight when the process received a
signal, dropping in-progress responses.

Fix: shut down BOTH servers with srv.Shutdown(ctx) on context cancellation,
with a 30-second drain timeout.

#13 — Missing security headers
SecurityHeadersMiddleware only set X-Content-Type-Options, X-Frame-Options,
Referrer-Policy, and X-XSS-Protection. Missing HSTS, CSP, Permissions-Policy.
Token responses had no Cache-Control.

Fix:
- Permissions-Policy disabling geolocation/microphone/camera/payment/usb
- Strict-Transport-Security gated behind a new --enable-hsts flag (default
  off — operators not behind TLS would lock browsers out for a year)
- Content-Security-Policy on by default with a conservative starting policy
  (frame-ancestors 'none' replaces X-Frame-Options as the modern equivalent)
  and a --disable-csp escape hatch for dashboards we haven't tightened yet
- /oauth/token responses now set Cache-Control: no-store, no-cache,
  must-revalidate, private (RFC 6749 §5.1) and Pragma: no-cache
@lakhansamani lakhansamani merged commit 4ce890a into main Apr 7, 2026
@lakhansamani lakhansamani deleted the security/server-hardening branch April 7, 2026 04:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant