feat(backend): server hardening — timeouts, security headers, trusted-proxy client IP (closes #19)
check / check (push) Failing after 0s

Add ReadHeaderTimeout and IdleTimeout to the http.Server (named
constants beside the existing timeouts) to close the slowloris and
idle-keep-alive gaps.

Add a SecurityHeaders middleware setting HSTS, a JSON-API CSP
(default-src 'none'; frame-ancestors 'none'), X-Frame-Options: DENY,
X-Content-Type-Options: nosniff, Referrer-Policy, and Permissions-Policy.
It is registered before CORS so the headers ride on preflight responses.

Resolve the client IP from X-Forwarded-For / X-Real-IP only when the
direct peer is in a trusted-proxy allowlist, defaulting to loopback plus
RFC1918 and configurable via TRUSTED_PROXIES; an untrusted peer's
forwarded headers are ignored and the direct peer is logged. Uses
net/netip; no new dependency.

Model: opus-4-8
This commit is contained in:
2026-09-21 12:49:58 +00:00
parent f7c7f92e27
commit 911dfbb825
8 changed files with 347 additions and 16 deletions
+11 -5
View File
@@ -42,11 +42,17 @@ Internal packages in `internal/` follow standard Go project layout:
### Configuration
| Variable | Default | Description |
| ---------- | ------------------ | --------------------------------- |
| `PORT` | `8080` | HTTP listen port |
| `DATA_DIR` | `./data/reports` | Directory for compressed reports |
| `DEBUG` | `false` | Enable debug logging |
| Variable | Default | Description |
| ----------------- | -------------------- | -------------------------------------------------------------------------------------------------------- |
| `PORT` | `8080` | HTTP listen port |
| `DATA_DIR` | `./data/reports` | Directory for compressed reports |
| `DEBUG` | `false` | Enable debug logging |
| `TRUSTED_PROXIES` | loopback + RFC1918 | Comma-separated CIDRs whose `X-Forwarded-For` / `X-Real-IP` headers are trusted for client IP resolution |
`TRUSTED_PROXIES` defaults to `127.0.0.1/32,::1/128,10.0.0.0/8,172.16.0.0/12,192.168.0.0/16`.
The loopback entries cover the reverse proxy that shares the container; the
RFC1918 ranges match `nginx.conf`. A request whose direct peer is outside this
set has its forwarded headers ignored, and the direct peer is logged instead.
### Report storage