From 0a72be280e92e15f5f7f0b02a162732b5d717294 Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Tue, 9 Jan 2018 21:33:54 +0000 Subject: [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 TryBot-Result: Gobot Gobot Reviewed-by: Ian Lance Taylor Reviewed-on: https://go-review.googlesource.com/88535 Run-TryBot: Andrew Bonventre --- src/net/url/url.go | 33 +++++++++++++++++++++++++++++++++ src/net/url/url_test.go | 7 +++++++ 2 files changed, 40 insertions(+) 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) + } +} -- cgit v1.2.3-54-g00ecf