package lk import ( "net/http" "testing" ) // H2: X-Forwarded-For/X-Real-IP от НЕдоверенного источника не должны подменять IP. func TestClientIPTrust(t *testing.T) { req := func(remote string, hdr map[string]string) *http.Request { r, _ := http.NewRequest("POST", "/login", nil) r.RemoteAddr = remote for k, v := range hdr { r.Header.Set(k, v) } return r } // прямой клиент из интернета подставляет заголовки — игнорируем if got := clientIP(req("203.0.113.7:5000", map[string]string{"X-Real-IP": "1.2.3.4", "X-Forwarded-For": "9.9.9.9"})); got != "203.0.113.7" { t.Errorf("недоверенный источник: ожидали 203.0.113.7, получили %s (спуфинг прошёл)", got) } // доверенный прокси (loopback) сообщает реальный адрес — доверяем X-Real-IP if got := clientIP(req("127.0.0.1:5000", map[string]string{"X-Real-IP": "1.2.3.4"})); got != "1.2.3.4" { t.Errorf("loopback X-Real-IP: ожидали 1.2.3.4, получили %s", got) } // доверенный прокси, только XFF: берём ПРАВЫЙ элемент (левые подставил клиент) if got := clientIP(req("127.0.0.1:5000", map[string]string{"X-Forwarded-For": "9.9.9.9, 5.6.7.8"})); got != "5.6.7.8" { t.Errorf("loopback XFF: ожидали правый 5.6.7.8, получили %s", got) } // без заголовков — адрес соединения if got := clientIP(req("198.51.100.2:443", nil)); got != "198.51.100.2" { t.Errorf("без заголовков: ожидали 198.51.100.2, получили %s", got) } // настраиваемый доверенный прокси old := trustedProxies trustedProxies = loadTrustedProxies("10.0.0.0/8") defer func() { trustedProxies = old }() if got := clientIP(req("10.1.2.3:5000", map[string]string{"X-Real-IP": "1.2.3.4"})); got != "1.2.3.4" { t.Errorf("доверенный CIDR: ожидали 1.2.3.4, получили %s", got) } }