A new internal/clientip says who sent a request and how: the connection's address, scheme and Host, or through a configured proxy what it forwarded. The base URL in pages and setup scripts, isHTTPS for cookies, and the per-address limits of auth and the sign-in forms use it. /setup scripts are no-store. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
35 lines
1.1 KiB
Go
35 lines
1.1 KiB
Go
package clientip
|
|
|
|
import (
|
|
"net/http/httptest"
|
|
"testing"
|
|
)
|
|
|
|
func TestForwardingHeadersAreBelievedOnlyFromTrustedProxies(t *testing.T) {
|
|
r := httptest.NewRequest("GET", "/setup/x", nil)
|
|
r.RemoteAddr = "203.0.113.9:4000"
|
|
r.Header.Set("X-Forwarded-For", "10.9.9.9")
|
|
r.Header.Set("X-Forwarded-Host", "evil.example")
|
|
r.Header.Set("X-Forwarded-Proto", "https")
|
|
r.Host = "gw.example:8080"
|
|
|
|
SetTrusted(nil)
|
|
if Addr(r) != "203.0.113.9" || Host(r) != "gw.example:8080" || Proto(r) != "http" {
|
|
t.Errorf("believed an untrusted client: %s %s %s", Addr(r), Host(r), Proto(r))
|
|
}
|
|
|
|
if bad := SetTrusted([]string{"203.0.113.0/24", "10.0.0.5", "nonsense"}); len(bad) != 1 {
|
|
t.Errorf("skipped %v", bad)
|
|
}
|
|
r.Header.Set("X-Forwarded-For", "198.51.100.7, 10.0.0.5")
|
|
if Addr(r) != "198.51.100.7" || Host(r) != "evil.example" || Proto(r) != "https" {
|
|
t.Errorf("through trusted proxies: %s %s %s", Addr(r), Host(r), Proto(r))
|
|
}
|
|
// A client prepending addresses gains nothing: the nearest untrusted one
|
|
// is the one the proxy saw.
|
|
r.Header.Set("X-Forwarded-For", "1.2.3.4, 198.51.100.7")
|
|
if Addr(r) != "198.51.100.7" {
|
|
t.Errorf("spoofed: %s", Addr(r))
|
|
}
|
|
}
|