mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/url: disallow raw IPv6 addresses in host
RFC 3986 requires square brackets around IPv6 addresses. Parse's acceptance of raw IPv6 addresses is non compliant, and complicates splitting out a port. This is a resubmission of CL 710176 after the revert in CL 711800, this time with a new urlstrictipv6 godebug to control the behavior. Fixes #31024 Fixes #75223 Change-Id: I4cbe5bb84266b3efe9c98cf4300421ddf1df7291 Reviewed-on: https://go-review.googlesource.com/c/go/+/712840 Reviewed-by: Junyang Shao <shaojunyang@google.com> Reviewed-by: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
This commit is contained in:
parent
4e761b9a18
commit
0c28789bd7
6 changed files with 49 additions and 21 deletions
|
|
@ -163,6 +163,11 @@ will fail early. The default value is `httpcookiemaxnum=3000`. Setting
|
|||
number of cookies. To avoid denial of service attacks, this setting and default
|
||||
was backported to Go 1.25.2 and Go 1.24.8.
|
||||
|
||||
Go 1.26 added a new `urlstrictcolons` setting that controls whether `net/url.Parse`
|
||||
allows malformed hostnames containing colons outside of a bracketed IPv6 address.
|
||||
The default `urlstrictcolons=1` rejects URLs such as `http://localhost:1:2` or `http://::1/`.
|
||||
Colons are permitted as part of a bracketed IPv6 address, such as `http://[::1]/`.
|
||||
|
||||
### Go 1.25
|
||||
|
||||
Go 1.25 added a new `decoratemappings` setting that controls whether the Go
|
||||
|
|
|
|||
4
doc/next/6-stdlib/99-minor/net/url/31024.md
Normal file
4
doc/next/6-stdlib/99-minor/net/url/31024.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
[Parse] now rejects malformed URLs containing colons in the host subcomponent,
|
||||
such as `http://::1/` or `http://localhost:80:80/`.
|
||||
URLs containing bracketed IPv6 addresses, such as `http://[::1]/` are still accepted.
|
||||
The new GODEBUG=urlstrictcolons=0 setting restores the old behavior.
|
||||
|
|
@ -67,6 +67,7 @@ var All = []Info{
|
|||
{Name: "tlssha1", Package: "crypto/tls", Changed: 25, Old: "1"},
|
||||
{Name: "tlsunsafeekm", Package: "crypto/tls", Changed: 22, Old: "1"},
|
||||
{Name: "updatemaxprocs", Package: "runtime", Changed: 25, Old: "0"},
|
||||
{Name: "urlstrictcolons", Package: "net/url", Changed: 26, Old: "0"},
|
||||
{Name: "winreadlinkvolume", Package: "os", Changed: 23, Old: "0"},
|
||||
{Name: "winsymlink", Package: "os", Changed: 23, Old: "0"},
|
||||
{Name: "x509keypairleaf", Package: "crypto/tls", Changed: 23, Old: "0"},
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package url
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/godebug"
|
||||
"net/netip"
|
||||
"path"
|
||||
"slices"
|
||||
|
|
@ -26,6 +27,8 @@ import (
|
|||
_ "unsafe" // for linkname
|
||||
)
|
||||
|
||||
var urlstrictcolons = godebug.New("urlstrictcolons")
|
||||
|
||||
// Error reports an error and the operation and URL that caused it.
|
||||
type Error struct {
|
||||
Op string
|
||||
|
|
@ -599,7 +602,11 @@ func parseHost(host string) (string, error) {
|
|||
return "", errors.New("invalid IP-literal")
|
||||
}
|
||||
return "[" + unescapedHostname + "]" + unescapedColonPort, nil
|
||||
} else if i := strings.LastIndex(host, ":"); i != -1 {
|
||||
} else if i := strings.Index(host, ":"); i != -1 {
|
||||
if j := strings.LastIndex(host, ":"); urlstrictcolons.Value() == "0" && j != i {
|
||||
urlstrictcolons.IncNonDefault()
|
||||
i = j
|
||||
}
|
||||
colonPort := host[i:]
|
||||
if !validOptionalPort(colonPort) {
|
||||
return "", fmt.Errorf("invalid port %q after host", colonPort)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import (
|
|||
"io"
|
||||
"net"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
|
@ -506,26 +507,6 @@ var urltests = []URLTest{
|
|||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
// Malformed IPv6 but still accepted.
|
||||
"http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:8080/foo",
|
||||
&URL{
|
||||
Scheme: "http",
|
||||
Host: "2b01:e34:ef40:7730:8e70:5aff:fefe:edac:8080",
|
||||
Path: "/foo",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
// Malformed IPv6 but still accepted.
|
||||
"http://2b01:e34:ef40:7730:8e70:5aff:fefe:edac:/foo",
|
||||
&URL{
|
||||
Scheme: "http",
|
||||
Host: "2b01:e34:ef40:7730:8e70:5aff:fefe:edac:",
|
||||
Path: "/foo",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"http://[2b01:e34:ef40:7730:8e70:5aff:fefe:edac]:8080/foo",
|
||||
&URL{
|
||||
|
|
@ -735,6 +716,9 @@ var parseRequestURLTests = []struct {
|
|||
{"https://[0:0::test.com]:80", false},
|
||||
{"https://[2001:db8::test.com]", false},
|
||||
{"https://[test.com]", false},
|
||||
{"https://1:2:3:4:5:6:7:8", false},
|
||||
{"https://1:2:3:4:5:6:7:8:80", false},
|
||||
{"https://example.com:80:", false},
|
||||
}
|
||||
|
||||
func TestParseRequestURI(t *testing.T) {
|
||||
|
|
@ -2280,3 +2264,25 @@ func TestJoinPath(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseStrictIpv6(t *testing.T) {
|
||||
t.Setenv("GODEBUG", "urlstrictcolons=0")
|
||||
|
||||
tests := []struct {
|
||||
url string
|
||||
}{
|
||||
// Malformed URLs that used to parse.
|
||||
{"https://1:2:3:4:5:6:7:8"},
|
||||
{"https://1:2:3:4:5:6:7:8:80"},
|
||||
{"https://example.com:80:"},
|
||||
}
|
||||
for i, tc := range tests {
|
||||
t.Run(strconv.Itoa(i), func(t *testing.T) {
|
||||
_, err := Parse(tc.url)
|
||||
if err != nil {
|
||||
t.Errorf("Parse(%q) error = %v, want nil", tc.url, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -399,6 +399,11 @@ Below is the full list of supported metrics, ordered lexicographically.
|
|||
The number of non-default behaviors executed by the runtime
|
||||
package due to a non-default GODEBUG=updatemaxprocs=... setting.
|
||||
|
||||
/godebug/non-default-behavior/urlstrictcolons:events
|
||||
The number of non-default behaviors executed by the net/url
|
||||
package due to a non-default GODEBUG=urlstrictcolons=...
|
||||
setting.
|
||||
|
||||
/godebug/non-default-behavior/winreadlinkvolume:events
|
||||
The number of non-default behaviors executed by the os package
|
||||
due to a non-default GODEBUG=winreadlinkvolume=... setting.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue