From 52f43605432ae6ef5ac9578289fcf555ee4f32e4 Mon Sep 17 00:00:00 2001 From: Blake Stoddard Date: Thu, 10 Sep 2020 04:40:59 -0400 Subject: [PATCH] Add option to disable following redirects (#237) When redirects are followed, ensure that they are still allowed per AllowHosts/DenyHosts --- cmd/imageproxy/main.go | 2 ++ imageproxy.go | 21 ++++++++++++++++++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/cmd/imageproxy/main.go b/cmd/imageproxy/main.go index f906d16..25e6278 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 a2f4d22..11e4077 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,21 @@ 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 { + // 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) || (len(p.AllowHosts) > 0 && !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 + } + } resp, err := p.Client.Do(actualReq) if err != nil { @@ -271,7 +289,8 @@ 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" ) // allowed determines whether the specified request contains an allowed