]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.9] net/url: reject invalid userinfo values when parsing URLs
authorBrad Fitzpatrick <bradfitz@golang.org>
Tue, 9 Jan 2018 21:33:54 +0000 (21:33 +0000)
committerAndrew Bonventre <andybons@golang.org>
Mon, 22 Jan 2018 20:25:12 +0000 (20:25 +0000)
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>

src/net/url/url.go
src/net/url/url_test.go

index 2ac24725692f89f3c1e87c5023d12d8352856362..70556a49b83ca139244424d38840d43cda6476c8 100644 (file)
@@ -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
+}
index 6c3bb21d20cb367d8823b364e91ed8f69c349af3..5d9741202353cdf9eb1d457981059aaf8732b464 100644 (file)
@@ -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)
+       }
+}