1
0
mirror of https://github.com/golang/go synced 2024-11-17 03:04:44 -07:00

net/http: keep sensitive headers on redirects to the same host

Fixes #35104
This commit is contained in:
Gustavo Falco 2022-08-19 00:14:25 -03:00
parent 9b8750f53e
commit 8d53e71e22
3 changed files with 33 additions and 10 deletions

View File

@ -990,8 +990,8 @@ func shouldCopyHeaderOnRedirect(headerKey string, initial, dest *url.URL) bool {
// directly, we don't know their scope, so we assume
// it's for *.domain.com.
ihost := canonicalAddr(initial)
dhost := canonicalAddr(dest)
ihost := idnaASCIIFromURL(initial)
dhost := idnaASCIIFromURL(dest)
return isDomainOrSubdomain(dhost, ihost)
}
// All other headers are copied:

View File

@ -1470,6 +1470,9 @@ func TestClientRedirectResponseWithoutRequest(t *testing.T) {
}
// Issue 4800: copy (some) headers when Client follows a redirect.
// Issue 35104: Since both URLs have the same host (localhost)
// but different ports, sensitive headers like Cookie and Authorization
// are preserved.
func TestClientCopyHeadersOnRedirect(t *testing.T) { run(t, testClientCopyHeadersOnRedirect) }
func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
const (
@ -1483,6 +1486,8 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
"X-Foo": []string{xfoo},
"Referer": []string{ts2URL},
"Accept-Encoding": []string{"gzip"},
"Cookie": []string{"foo=bar"},
"Authorization": []string{"secretpassword"},
}
if !reflect.DeepEqual(r.Header, want) {
t.Errorf("Request.Header = %#v; want %#v", r.Header, want)
@ -1504,6 +1509,8 @@ func testClientCopyHeadersOnRedirect(t *testing.T, mode testMode) {
"User-Agent": []string{ua},
"X-Foo": []string{xfoo},
"Referer": []string{ts2URL},
"Cookie": []string{"foo=bar"},
"Authorization": []string{"secretpassword"},
}
if !reflect.DeepEqual(r.Header, want) {
t.Errorf("CheckRedirect Request.Header = %#v; want %#v", r.Header, want)
@ -1707,18 +1714,30 @@ func TestShouldCopyHeaderOnRedirect(t *testing.T) {
{"cookie", "http://foo.com/", "http://bar.com/", false},
{"cookie2", "http://foo.com/", "http://bar.com/", false},
{"authorization", "http://foo.com/", "http://bar.com/", false},
{"authorization", "http://foo.com/", "https://foo.com/", true},
{"authorization", "http://foo.com:1234/", "http://foo.com:4321/", true},
{"www-authenticate", "http://foo.com/", "http://bar.com/", false},
// But subdomains should work:
{"www-authenticate", "http://foo.com/", "http://foo.com/", true},
{"www-authenticate", "http://foo.com/", "http://sub.foo.com/", true},
{"www-authenticate", "http://foo.com/", "http://notfoo.com/", false},
{"www-authenticate", "http://foo.com/", "https://foo.com/", false},
{"www-authenticate", "http://foo.com/", "https://foo.com/", true},
{"www-authenticate", "http://foo.com:80/", "http://foo.com/", true},
{"www-authenticate", "http://foo.com:80/", "http://sub.foo.com/", true},
{"www-authenticate", "http://foo.com:443/", "https://foo.com/", true},
{"www-authenticate", "http://foo.com:443/", "https://sub.foo.com/", true},
{"www-authenticate", "http://foo.com:1234/", "http://foo.com/", false},
{"www-authenticate", "http://foo.com:1234/", "http://foo.com/", true},
{"authorization", "http://foo.com/", "http://foo.com/", true},
{"authorization", "http://foo.com/", "http://sub.foo.com/", true},
{"authorization", "http://foo.com/", "http://notfoo.com/", false},
{"authorization", "http://foo.com/", "https://foo.com/", true},
{"authorization", "http://foo.com:80/", "http://foo.com/", true},
{"authorization", "http://foo.com:80/", "http://sub.foo.com/", true},
{"authorization", "http://foo.com:443/", "https://foo.com/", true},
{"authorization", "http://foo.com:443/", "https://sub.foo.com/", true},
{"authorization", "http://foo.com:1234/", "http://foo.com/", true},
}
for i, tt := range tests {
u0, err := url.Parse(tt.initialURL)

View File

@ -2743,17 +2743,21 @@ var portMap = map[string]string{
"socks5": "1080",
}
// canonicalAddr returns url.Host but always with a ":port" suffix.
func canonicalAddr(url *url.URL) string {
func idnaASCIIFromURL(url *url.URL) string {
addr := url.Hostname()
if v, err := idnaASCII(addr); err == nil {
addr = v
}
return addr
}
// canonicalAddr returns url.Host but always with a ":port" suffix.
func canonicalAddr(url *url.URL) string {
port := url.Port()
if port == "" {
port = portMap[url.Scheme]
}
return net.JoinHostPort(addr, port)
return net.JoinHostPort(idnaASCIIFromURL(url), port)
}
// bodyEOFSignal is used by the HTTP/1 transport when reading response