Allow disabling of all X-Forwarded-For header processing (#20977)

This commit is contained in:
Mark Theunissen 2025-02-26 20:25:49 +01:00 committed by GitHub
parent f129fd48f2
commit 7cc0c69228
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 58 additions and 22 deletions

View File

@ -26,6 +26,9 @@ import (
"net/http" "net/http"
"regexp" "regexp"
"strings" "strings"
"github.com/minio/minio/internal/config"
"github.com/minio/pkg/v3/env"
) )
var ( var (
@ -51,6 +54,9 @@ var (
protoRegex = regexp.MustCompile(`(?i)^(;|,| )+(?:proto=)(https|http)`) protoRegex = regexp.MustCompile(`(?i)^(;|,| )+(?:proto=)(https|http)`)
) )
// Used to disable all processing of the X-Forwarded-For header in source IP discovery.
var enableXFFHeader = env.Get("_MINIO_API_XFF_HEADER", config.EnableOn) == config.EnableOn
// GetSourceScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239 // GetSourceScheme retrieves the scheme from the X-Forwarded-Proto and RFC7239
// Forwarded headers (in that order). // Forwarded headers (in that order).
func GetSourceScheme(r *http.Request) string { func GetSourceScheme(r *http.Request) string {
@ -84,29 +90,35 @@ func GetSourceScheme(r *http.Request) string {
func GetSourceIPFromHeaders(r *http.Request) string { func GetSourceIPFromHeaders(r *http.Request) string {
var addr string var addr string
if fwd := r.Header.Get(xForwardedFor); fwd != "" { if enableXFFHeader {
// Only grab the first (client) address. Note that '192.168.0.1, if fwd := r.Header.Get(xForwardedFor); fwd != "" {
// 10.1.1.1' is a valid key for X-Forwarded-For where addresses after // Only grab the first (client) address. Note that '192.168.0.1,
// the first may represent forwarding proxies earlier in the chain. // 10.1.1.1' is a valid key for X-Forwarded-For where addresses after
s := strings.Index(fwd, ", ") // the first may represent forwarding proxies earlier in the chain.
if s == -1 { s := strings.Index(fwd, ", ")
s = len(fwd) if s == -1 {
s = len(fwd)
}
addr = fwd[:s]
} }
addr = fwd[:s] }
} else if fwd := r.Header.Get(xRealIP); fwd != "" {
// X-Real-IP should only contain one IP address (the client making the if addr == "" {
// request). if fwd := r.Header.Get(xRealIP); fwd != "" {
addr = fwd // X-Real-IP should only contain one IP address (the client making the
} else if fwd := r.Header.Get(forwarded); fwd != "" { // request).
// match should contain at least two elements if the protocol was addr = fwd
// specified in the Forwarded header. The first element will always be } else if fwd := r.Header.Get(forwarded); fwd != "" {
// the 'for=' capture, which we ignore. In the case of multiple IP // match should contain at least two elements if the protocol was
// addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only // specified in the Forwarded header. The first element will always be
// extract the first, which should be the client IP. // the 'for=' capture, which we ignore. In the case of multiple IP
if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 { // addresses (for=8.8.8.8, 8.8.4.4, 172.16.1.20 is valid) we only
// IPv6 addresses in Forwarded headers are quoted-strings. We strip // extract the first, which should be the client IP.
// these quotes. if match := forRegex.FindStringSubmatch(fwd); len(match) > 1 {
addr = strings.Trim(match[1], `"`) // IPv6 addresses in Forwarded headers are quoted-strings. We strip
// these quotes.
addr = strings.Trim(match[1], `"`)
}
} }
} }

View File

@ -84,3 +84,27 @@ func TestGetSourceIP(t *testing.T) {
} }
} }
} }
func TestXFFDisabled(t *testing.T) {
req := &http.Request{
Header: http.Header{
xForwardedFor: []string{"8.8.8.8"},
xRealIP: []string{"1.1.1.1"},
},
}
// When X-Forwarded-For and X-Real-IP headers are both present, X-Forwarded-For takes precedence.
res := GetSourceIP(req)
if res != "8.8.8.8" {
t.Errorf("wrong header, xff takes precedence: got %s, want: 8.8.8.8", res)
}
// When explicitly disabled, the XFF header is ignored and X-Real-IP is used.
enableXFFHeader = false
defer func() {
enableXFFHeader = true
}()
res = GetSourceIP(req)
if res != "1.1.1.1" {
t.Errorf("wrong header, xff is disabled: got %s, want: 1.1.1.1", res)
}
}