]> Cypherpunks repositories - gostls13.git/commitdiff
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)
committerBrad Fitzpatrick <bradfitz@golang.org>
Wed, 10 Jan 2018 01:37:18 +0000 (01:37 +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>
src/net/url/url.go
src/net/url/url_test.go

index 7c3d24493e0960d2b7072db37d773f149287e81a..3e1217954220389c08b0ce086f131dde9052f187 100644 (file)
@@ -563,6 +563,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
@@ -1069,3 +1072,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 d6aed3acafab977dc690832e52b6a3c8cd608d82..f2d311a9986975a6733f60df25643a6c4c841f21 100644 (file)
@@ -1735,3 +1735,10 @@ func TestNilUser(t *testing.T) {
                t.Fatalf("expected empty string, got %s", v)
        }
 }
+
+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)
+       }
+}