diff options
author | Brad Fitzpatrick <bradfitz@golang.org> | 2018-01-09 21:33:54 +0000 |
---|---|---|
committer | Andrew Bonventre <andybons@golang.org> | 2018-01-22 20:25:12 +0000 |
commit | 0a72be280e92e15f5f7f0b02a162732b5d717294 (patch) | |
tree | 37d5707f54d8b5aba6b76ace46f434e1e5f74b1d | |
parent | e36f34fa55f1afaa3d5b731dadacb0145f2d928c (diff) | |
download | go-0a72be280e92e15f5f7f0b02a162732b5d717294.tar.gz go-0a72be280e92e15f5f7f0b02a162732b5d717294.zip |
[release-branch.go1.9] net/url: reject invalid userinfo values when parsing URLs
Fixes #23392
Change-Id: I5822b082b14d886b9c3b5ad7beebb2c01a77851b
Reviewed-on: https://go-review.googlesource.com/87038
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Reviewed-on: https://go-review.googlesource.com/88535
Run-TryBot: Andrew Bonventre <andybons@golang.org>
-rw-r--r-- | src/net/url/url.go | 33 | ||||
-rw-r--r-- | src/net/url/url_test.go | 7 |
2 files changed, 40 insertions, 0 deletions
diff --git a/src/net/url/url.go b/src/net/url/url.go index 2ac2472569..70556a49b8 100644 --- a/src/net/url/url.go +++ b/src/net/url/url.go @@ -545,6 +545,9 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) { return nil, host, nil } userinfo := authority[:i] + if !validUserinfo(userinfo) { + return nil, "", errors.New("net/url: invalid userinfo") + } if !strings.Contains(userinfo, ":") { if userinfo, err = unescape(userinfo, encodeUserPassword); err != nil { return nil, "", err @@ -1051,3 +1054,33 @@ func (u *URL) UnmarshalBinary(text []byte) error { *u = *u1 return nil } + +// validUserinfo reports whether s is a valid userinfo string per RFC 3986 +// Section 3.2.1: +// userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) +// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +// / "*" / "+" / "," / ";" / "=" +// +// It doesn't validate pct-encoded. The caller does that via func unescape. +func validUserinfo(s string) bool { + for _, r := range s { + if 'A' <= r && r <= 'Z' { + continue + } + if 'a' <= r && r <= 'z' { + continue + } + if '0' <= r && r <= '9' { + continue + } + switch r { + case '-', '.', '_', ':', '~', '!', '$', '&', '\'', + '(', ')', '*', '+', ',', ';', '=', '%', '@': + continue + default: + return false + } + } + return true +} diff --git a/src/net/url/url_test.go b/src/net/url/url_test.go index 6c3bb21d20..5d97412023 100644 --- a/src/net/url/url_test.go +++ b/src/net/url/url_test.go @@ -1683,3 +1683,10 @@ func TestGob(t *testing.T) { t.Errorf("json decoded to: %s\nwant: %s\n", u1, u) } } + +func TestInvalidUserPassword(t *testing.T) { + _, err := Parse("http://us\ner:pass\nword@foo.com/") + if got, wantsub := fmt.Sprint(err), "net/url: invalid userinfo"; !strings.Contains(got, wantsub) { + t.Errorf("error = %q; want substring %q", got, wantsub) + } +} |