Files
palette/internal/api/clientip.go
T
fen b99e1bdb27
CI / test (pull_request) Successful in 26s
CI / docker (pull_request) Skipped
Fix #280 follow-up: remove PALETTE_TRUSTED_IP_HEADER
Per owner decision the optional proxy-header escape hatch is dead config:
remove the env var, its plumbing (Config.TrustedIPHeader, SetTrustedIPHeader),
and the README row. Rate-limit keying is always the peer address; no
client-supplied IP header is ever trusted. Tests updated to assert headers
(CF-Connecting-IP included) never influence clientIP.
2026-09-17 20:45:54 -05:00

28 lines
961 B
Go

// clientIP extracts the client IP for rate-limit keying.
//
// Trust boundary (issue #280): the bucket key MUST NOT come from any header a
// client can influence. The previous rightmost-X-Forwarded-For scheme (#85)
// assumed Traefik appends the real client IP, but the deployed ingress does
// not rewrite XFF, so a client rotating its own XFF value got a fresh bucket
// per request and the limit was unenforceable (pentest H1: 6x201 across 8
// rotating-XFF creates).
//
// The bucket key is always the actual peer address (RemoteAddr). Behind any
// reverse proxy this is the proxy's address, so all clients share one bucket
// per endpoint — coarse, but safe. Client-supplied IP headers
// (X-Forwarded-For, X-Real-Ip, and any others) are never trusted.
package api
import (
"net"
"net/http"
)
func clientIP(r *http.Request) string {
host := r.RemoteAddr
if h, _, err := net.SplitHostPort(r.RemoteAddr); err == nil {
host = h
}
return host
}