Owner follow-up to the #280 fix (PR #284): the trusted-header env var is gone. clientIP() now uses the peer address exclusively and ignores all client-supplied IP headers; the env var row is removed from the README.
28 lines
943 B
Go
28 lines
943 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 the actual peer address (RemoteAddr) only. 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) 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
|
|
}
|