diff --git a/app/vmauth/main.go b/app/vmauth/main.go index e1d110be4..4a444e3b2 100644 --- a/app/vmauth/main.go +++ b/app/vmauth/main.go @@ -54,7 +54,7 @@ func requestHandler(w http.ResponseWriter, r *http.Request) bool { } info.requests.Inc() - targetURL := info.URLPrefix + r.RequestURI + targetURL := createTargetURL(info.URLPrefix, r.URL) if _, err := url.Parse(targetURL); err != nil { httpserver.Errorf(w, "Invalid targetURL=%q: %s", targetURL, err) return true diff --git a/app/vmauth/target_url.go b/app/vmauth/target_url.go new file mode 100644 index 000000000..e570c2a9c --- /dev/null +++ b/app/vmauth/target_url.go @@ -0,0 +1,16 @@ +package main + +import ( + "net/url" + "path" + "strings" +) + +func createTargetURL(prefix string, u *url.URL) string { + // Prevent from attacks with using `..` in r.URL.Path + u.Path = path.Clean(u.Path) + if !strings.HasPrefix(u.Path, "/") { + u.Path = "/" + u.Path + } + return prefix + u.RequestURI() +} diff --git a/app/vmauth/target_url_test.go b/app/vmauth/target_url_test.go new file mode 100644 index 000000000..fbe51043d --- /dev/null +++ b/app/vmauth/target_url_test.go @@ -0,0 +1,26 @@ +package main + +import ( + "net/url" + "testing" +) + +func TestCreateTargetURL(t *testing.T) { + f := func(prefix, requestURI, expectedTarget string) { + t.Helper() + u, err := url.Parse(requestURI) + if err != nil { + t.Fatalf("cannot parse %q: %s", requestURI, err) + } + target := createTargetURL(prefix, u) + if target != expectedTarget { + t.Fatalf("unexpected target; got %q; want %q", target, expectedTarget) + } + } + f("http://foo.bar", "", "http://foo.bar/.") + f("http://foo.bar", "/", "http://foo.bar/") + f("http://foo.bar", "a/b?c=d", "http://foo.bar/a/b?c=d") + f("https://sss:3894/x/y", "/z", "https://sss:3894/x/y/z") + f("https://sss:3894/x/y", "/../../aaa", "https://sss:3894/x/y/aaa") + f("https://sss:3894/x/y", "/./asd/../../aaa?a=d&s=s/../d", "https://sss:3894/x/y/aaa?a=d&s=s/../d") +}