Fix rate limiter bypass via client-controlled X-Forwarded-For (#280)
clientIP() keyed rate-limit buckets on the rightmost X-Forwarded-For entry, assuming traefik appends the real client IP. The deployed ingress does not rewrite XFF, so rotating the header gave a fresh bucket per request (pentest H1: 8 creates with rotating XFF -> 6x201). Now the bucket keys on the actual peer address (RemoteAddr) by default; every client-supplied IP header is ignored. Deployments whose ingress overwrites a client-IP header can opt in via PALETTE_TRUSTED_IP_HEADER (e.g. CF-Connecting-IP behind Cloudflare) to restore per-client limits. Adds tests: rotating XFF no longer resets the bucket; the trusted header is honored only when explicitly configured.
This commit is contained in:
@@ -70,6 +70,7 @@ go build -o palette ./cmd/palette
|
||||
| `PALETTE_ADMIN_KEY` | generated | Admin key; if unset a 32-char hex key is generated and persisted to `<db-dir>/admin-key` (0600) |
|
||||
| `PALETTE_DEFAULT_DARK` | dark on | Default dark mode for new visitors. Set `false`, `0`, or `off` to default to light mode. Visitors who toggle dark mode keep their choice in their browser. |
|
||||
| `PALETTE_UNLOCK_SECRET` | random per start | HMAC secret for password-unlock cookies. Set a fixed value to keep unlock sessions across restarts or across replicas. |
|
||||
| `PALETTE_TRUSTED_IP_HEADER` | unset | Name of a proxy-controlled client-IP header to key API rate limits on (e.g. `CF-Connecting-IP` when Cloudflare is the ingress; Cloudflare strips any client-supplied value). Unset: rate limits key on the peer address only, and all client-supplied IP headers (X-Forwarded-For, X-Real-Ip) are ignored. (#280) |
|
||||
|
||||
An `/admin` page exists for runtime settings, protected by a key set at
|
||||
install (`PALETTE_ADMIN_KEY` env var) and resettable locally. See
|
||||
|
||||
Reference in New Issue
Block a user