aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrad Fitzpatrick <bradfitz@golang.org>2018-01-09 21:33:54 +0000
committerAndrew Bonventre <andybons@golang.org>2018-01-22 20:25:12 +0000
commit0a72be280e92e15f5f7f0b02a162732b5d717294 (patch)
tree37d5707f54d8b5aba6b76ace46f434e1e5f74b1d
parente36f34fa55f1afaa3d5b731dadacb0145f2d928c (diff)
downloadgo-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.go33
-rw-r--r--src/net/url/url_test.go7
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)
+ }
+}