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:
@@ -28,6 +28,10 @@ type Config struct {
|
||||
DBPath string
|
||||
MaxTextBytes int64
|
||||
MaxItemBytes int64
|
||||
// TrustedIPHeader optionally names a proxy-controlled client-IP header
|
||||
// (e.g. CF-Connecting-IP behind Cloudflare) to key rate limits on. Empty
|
||||
// (default) keys on the peer address only. See clientip.go (#280).
|
||||
TrustedIPHeader string
|
||||
}
|
||||
|
||||
type apiServer struct {
|
||||
@@ -39,6 +43,7 @@ type apiServer struct {
|
||||
}
|
||||
|
||||
func NewServer(st *store.Store, cfg Config, ui *web.UI, ss *settingsStore, adminKey string) *apiServer {
|
||||
SetTrustedIPHeader(cfg.TrustedIPHeader) // #280
|
||||
return &apiServer{store: st, cfg: cfg, ui: ui, settings: ss, adminKey: adminKey}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user