From cc7d52abf8c84716bdbb76fa8a5ab16db1781686 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Fri, 19 Jun 2020 22:08:16 -0400 Subject: [PATCH 1/5] Add a -followRedirects flag that can be used to tell ImageProxy whether to follow redirects --- cmd/imageproxy/main.go | 2 ++ imageproxy.go | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/cmd/imageproxy/main.go b/cmd/imageproxy/main.go index 14b0b8bf1..9b7a57f0b 100644 --- a/cmd/imageproxy/main.go +++ b/cmd/imageproxy/main.go @@ -48,6 +48,7 @@ var allowHosts = flag.String("allowHosts", "", "comma separated list of allowed var denyHosts = flag.String("denyHosts", "", "comma separated list of denied remote hosts") var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts") var includeReferer = flag.Bool("includeReferer", false, "include referer header in remote requests") +var followRedirects = flag.Bool("followRedirects", true, "follow redirects") var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs") var cache tieredCache var signatureKeys signatureKeyList @@ -90,6 +91,7 @@ func main() { } p.IncludeReferer = *includeReferer + p.FollowRedirects = *followRedirects p.Timeout = *timeout p.ScaleUp = *scaleUp p.Verbose = *verbose diff --git a/imageproxy.go b/imageproxy.go index 16c887b5b..5452bd3ea 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -63,6 +63,9 @@ type Proxy struct { // is included in remote requests. IncludeReferer bool + // FollowRedirects controls whether imageproxy will follow redirects or not. + FollowRedirects bool + // DefaultBaseURL is the URL that relative remote URLs are resolved in // reference to. If nil, all remote URLs specified in requests must be // absolute. @@ -186,6 +189,11 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { // pass along the referer header from the original request copyHeader(actualReq.Header, r.Header, "referer") } + if !p.FollowRedirects { + p.Client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + } + } resp, err := p.Client.Do(actualReq) if err != nil { From 9a207af67a639dd362d15215c5cc2a92787b0179 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Fri, 19 Jun 2020 22:37:55 -0400 Subject: [PATCH 2/5] Ensure that the redirected host is allowed --- imageproxy.go | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/imageproxy.go b/imageproxy.go index 5452bd3ea..8447773e0 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -189,8 +189,19 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { // pass along the referer header from the original request copyHeader(actualReq.Header, r.Header, "referer") } - if !p.FollowRedirects { - p.Client.CheckRedirect = func(req *http.Request, via []*http.Request) error { + if p.FollowRedirects { + // FollowRedirects is true (default), ensure that the redirected host is allowed + p.Client.CheckRedirect = func(newreq *http.Request, via []*http.Request) error { + fmt.Printf("%v", newreq.URL) + if hostMatches(p.DenyHosts, newreq.URL) || hostMatches(p.AllowHosts, newreq.URL) { + http.Error(w, msgNotAllowedInRedirect, http.StatusForbidden) + return errNotAllowed + } + return nil + } + } else { + // FollowRedirects is false, don't follow redirects + p.Client.CheckRedirect = func(newreq *http.Request, via []*http.Request) error { return http.ErrUseLastResponse } } @@ -278,6 +289,7 @@ var ( errNotAllowed = errors.New("request does not contain an allowed host or valid signature") msgNotAllowed = "requested URL is not allowed" + msgNotAllowedInRedirect = "requested URL in redirect is not allowed" ) // allowed determines whether the specified request contains an allowed From 2fab7cf33bb64317af44888bf0a81ef66ab20799 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Fri, 19 Jun 2020 22:53:32 -0400 Subject: [PATCH 3/5] Drop debug line --- imageproxy.go | 1 - 1 file changed, 1 deletion(-) diff --git a/imageproxy.go b/imageproxy.go index 8447773e0..e0b057956 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -192,7 +192,6 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { if p.FollowRedirects { // FollowRedirects is true (default), ensure that the redirected host is allowed p.Client.CheckRedirect = func(newreq *http.Request, via []*http.Request) error { - fmt.Printf("%v", newreq.URL) if hostMatches(p.DenyHosts, newreq.URL) || hostMatches(p.AllowHosts, newreq.URL) { http.Error(w, msgNotAllowedInRedirect, http.StatusForbidden) return errNotAllowed From 47c56093b22a224043aae8fd917a40a72687d449 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Fri, 19 Jun 2020 22:59:12 -0400 Subject: [PATCH 4/5] gofmt is angry --- imageproxy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imageproxy.go b/imageproxy.go index e0b057956..14405f180 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -287,7 +287,7 @@ var ( errDeniedHost = errors.New("request contains a denied host") errNotAllowed = errors.New("request does not contain an allowed host or valid signature") - msgNotAllowed = "requested URL is not allowed" + msgNotAllowed = "requested URL is not allowed" msgNotAllowedInRedirect = "requested URL in redirect is not allowed" ) From d79103e4ccd30edac56ca2d777131e5f4ef55d95 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Wed, 24 Jun 2020 10:22:37 -0400 Subject: [PATCH 5/5] Fix the CheckRedirects logs to let items on AllowHosts through --- imageproxy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imageproxy.go b/imageproxy.go index 14405f180..81b681148 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -192,7 +192,7 @@ func (p *Proxy) serveImage(w http.ResponseWriter, r *http.Request) { if p.FollowRedirects { // FollowRedirects is true (default), ensure that the redirected host is allowed p.Client.CheckRedirect = func(newreq *http.Request, via []*http.Request) error { - if hostMatches(p.DenyHosts, newreq.URL) || hostMatches(p.AllowHosts, newreq.URL) { + if hostMatches(p.DenyHosts, newreq.URL) || (len(p.AllowHosts) > 0 && !hostMatches(p.AllowHosts, newreq.URL)) { http.Error(w, msgNotAllowedInRedirect, http.StatusForbidden) return errNotAllowed }