From 70276f36bc6aba1bf3cd13ede50344355fa66d68 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Sat, 15 Sep 2018 05:49:33 +0000 Subject: [PATCH] rename 'Whitelist' to 'RemoteHosts" This better describes what exactly is being allowed. --- README.md | 30 ++++++++++----------- cmd/imageproxy/main.go | 11 +++++--- etc/debian/etc-initd-imageproxy | 2 +- etc/imageproxy.conf | 2 +- etc/imageproxy.service | 2 +- imageproxy.go | 15 ++++++++--- imageproxy_test.go | 48 ++++++++++++++++----------------- 7 files changed, 61 insertions(+), 49 deletions(-) diff --git a/README.md b/README.md index e95b3e2..7e15891 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ imageproxy is a caching image proxy server written in go. It features: - basic image adjustments like resizing, cropping, and rotation - - access control using host whitelists or request signing (HMAC-SHA256) + - access control using allowed hosts list or request signing (HMAC-SHA256) - support for jpeg, png, webp (decode only), tiff, and gif image formats (including animated gifs) - caching in-memory, on disk, or with Amazon S3, Google Cloud Storage, Azure @@ -91,8 +91,8 @@ using: imageproxy -This will start the proxy on port 8080, without any caching and with no host -whitelist (meaning any remote URL can be proxied). Test this by navigating to +This will start the proxy on port 8080, without any caching and with no allowed +host list (meaning any remote URL can be proxied). Test this by navigating to and you should see a 500px square coder octocat. @@ -148,7 +148,7 @@ followed by a gcs bucket: [tiered fashion]: https://godoc.org/github.com/die-net/lrucache/twotier -### Referrer Whitelist ### +### Allowed Referrer List ### You can limit images to only be accessible for certain hosts in the HTTP referrer header, which can help prevent others from hotlinking to images. It can @@ -161,21 +161,21 @@ Reload the [codercat URL][], and you should now get an error message. You can specify multiple hosts as a comma separated list, or prefix a host value with `*.` to allow all sub-domains as well. -### Host whitelist ### +### Allowed Hosts List ### You can limit the remote hosts that the proxy will fetch images from using the -`whitelist` flag. This is useful, for example, for locking the proxy down to +`remoteHosts` flag. This is useful, for example, for locking the proxy down to your own hosts to prevent others from abusing it. Of course if you want to -support fetching from any host, leave off the whitelist flag. Try it out by +support fetching from any host, leave off the remoteHosts flag. Try it out by running: - imageproxy -whitelist example.com + imageproxy -remoteHosts example.com Reload the [codercat URL][], and you should now get an error message. You can specify multiple hosts as a comma separated list, or prefix a host value with `*.` to allow all sub-domains as well. -### Content-Type whitelist ### +### Allowed Content-Type List ### You can limit what content types can be proxied by using the `contentTypes` flag. By default, this is set to `image/*`, meaning that imageproxy will @@ -185,10 +185,10 @@ flag to an empty string to proxy all requests, regardless of content type. ### Signed Requests ### -Instead of a host whitelist, you can require that requests be signed. This is -useful in preventing abuse when you don't have just a static list of hosts you -want to allow. Signatures are generated using HMAC-SHA256 against the remote -URL, and url-safe base64 encoding the result: +Instead of an allowed host list, you can require that requests be signed. This +is useful in preventing abuse when you don't have just a static list of hosts +you want to allow. Signatures are generated using HMAC-SHA256 against the +remote URL, and url-safe base64 encoding the result: base64urlencode(hmac.New(sha256, ).digest()) @@ -209,8 +209,8 @@ Some simple code samples for generating signatures in various languages can be found in [URL Signing](https://github.com/willnorris/imageproxy/wiki/URL-signing). If both a whiltelist and signatureKey are specified, requests can match either. -In other words, requests that match one of the whitelisted hosts don't -necessarily need to be signed, though they can be. +In other words, requests that match one of the allowed hosts don't necessarily +need to be signed, though they can be. ### Default Base URL ### diff --git a/cmd/imageproxy/main.go b/cmd/imageproxy/main.go index 9de0b55..e9149f8 100644 --- a/cmd/imageproxy/main.go +++ b/cmd/imageproxy/main.go @@ -42,7 +42,8 @@ import ( const defaultMemorySize = 100 var addr = flag.String("addr", "localhost:8080", "TCP address to listen on") -var whitelist = flag.String("whitelist", "", "comma separated list of allowed remote hosts") +var remoteHosts = flag.String("remoteHosts", "", "comma separated list of allowed remote hosts") +var whitelist = flag.String("whitelist", "", "deprecated. use 'remoteHosts' instead") var referrers = flag.String("referrers", "", "comma separated list of allowed referring hosts") var baseURL = flag.String("baseURL", "", "default base URL for relative remote URLs") var cache tieredCache @@ -59,10 +60,14 @@ func init() { func main() { flag.Parse() + if *remoteHosts == "" { + // backwards compatible with old naming of the flag + *remoteHosts = *whitelist + } p := imageproxy.NewProxy(nil, cache.Cache) - if *whitelist != "" { - p.Whitelist = strings.Split(*whitelist, ",") + if *remoteHosts != "" { + p.RemoteHosts = strings.Split(*remoteHosts, ",") } if *referrers != "" { p.Referrers = strings.Split(*referrers, ",") diff --git a/etc/debian/etc-initd-imageproxy b/etc/debian/etc-initd-imageproxy index ce6007f..73dbae6 100644 --- a/etc/debian/etc-initd-imageproxy +++ b/etc/debian/etc-initd-imageproxy @@ -29,7 +29,7 @@ case "$1" in test -n "$ADDR" && DAEMON_OPTS+=" -addr=$ADDR" test -n "$CACHE" && DAEMON_OPTS+=" -cache=$CACHE" test -n "$LOG_DIR" && DAEMON_OPTS+=" -log_dir=$LOG_DIR" - test -n "$ALLOWED_REMOTE_HOSTS" && DAEMON_OPTS+=" -whitelist=$ALLOWED_REMOTE_HOSTS" + test -n "$ALLOWED_REMOTE_HOSTS" && DAEMON_OPTS+=" -remoteHosts=$ALLOWED_REMOTE_HOSTS" echo -n "Starting $NAME: " start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ diff --git a/etc/imageproxy.conf b/etc/imageproxy.conf index 9098acd..dae8466 100644 --- a/etc/imageproxy.conf +++ b/etc/imageproxy.conf @@ -11,4 +11,4 @@ exec start-stop-daemon --start -c www-data --exec /usr/bin/imageproxy -- \ -cache /var/cache/imageproxy \ -signatureKey @/etc/imageproxy.key \ -baseURL https://willnorris.com/ \ - -whitelist willnorris.com,notsoserendipitous.com,gabenorris.com + -remoteHosts willnorris.com,notsoserendipitous.com,gabenorris.com diff --git a/etc/imageproxy.service b/etc/imageproxy.service index ea02849..5c4d5af 100644 --- a/etc/imageproxy.service +++ b/etc/imageproxy.service @@ -9,7 +9,7 @@ ExecStart=/usr/local/bin/imageproxy \ -cache /var/cache/imageproxy \ -signatureKey @/etc/imageproxy.key \ -baseURL https://willnorris.com/ \ - -whitelist willnorris.com,notsoserendipitous.com,gabenorris.com + -remoteHosts willnorris.com,notsoserendipitous.com,gabenorris.com Restart=on-abort [Install] diff --git a/imageproxy.go b/imageproxy.go index 1b75499..26b6dd3 100644 --- a/imageproxy.go +++ b/imageproxy.go @@ -42,8 +42,11 @@ type Proxy struct { Client *http.Client // client used to fetch remote URLs Cache Cache // cache used to cache responses - // Whitelist specifies a list of remote hosts that images can be + // RemoteHosts specifies a list of remote hosts that images can be // proxied from. An empty list means all hosts are allowed. + RemoteHosts []string + + // Whitelist should no longer be used. Use "RemoteHosts" instead. Whitelist []string // Referrers, when given, requires that requests to the image @@ -207,15 +210,19 @@ func copyHeader(dst, src http.Header, keys ...string) { // referrer, host, and signature. It returns an error if the request is not // allowed. func (p *Proxy) allowed(r *Request) error { + if p.RemoteHosts == nil { + // backwards compatible with old naming of the field + p.RemoteHosts = p.Whitelist + } if len(p.Referrers) > 0 && !validReferrer(p.Referrers, r.Original) { return fmt.Errorf("request does not contain an allowed referrer: %v", r) } - if len(p.Whitelist) == 0 && len(p.SignatureKey) == 0 { - return nil // no whitelist or signature key, all requests accepted + if len(p.RemoteHosts) == 0 && len(p.SignatureKey) == 0 { + return nil // no allowed hosts or signature key, all requests accepted } - if len(p.Whitelist) > 0 && validHost(p.Whitelist, r.URL) { + if len(p.RemoteHosts) > 0 && validHost(p.RemoteHosts, r.URL) { return nil } diff --git a/imageproxy_test.go b/imageproxy_test.go index 199219c..0a62177 100644 --- a/imageproxy_test.go +++ b/imageproxy_test.go @@ -97,7 +97,7 @@ func TestCopyHeader(t *testing.T) { } func TestAllowed(t *testing.T) { - whitelist := []string{"good"} + remoteHosts := []string{"good"} key := []byte("c0ffee") genRequest := func(headers map[string]string) *http.Request { @@ -109,41 +109,41 @@ func TestAllowed(t *testing.T) { } tests := []struct { - url string - options Options - whitelist []string - referrers []string - key []byte - request *http.Request - allowed bool + url string + options Options + remoteHosts []string + referrers []string + key []byte + request *http.Request + allowed bool }{ - // no whitelist or signature key + // no remoteHosts or signature key {"http://test/image", emptyOptions, nil, nil, nil, nil, true}, - // whitelist - {"http://good/image", emptyOptions, whitelist, nil, nil, nil, true}, - {"http://bad/image", emptyOptions, whitelist, nil, nil, nil, false}, + // remoteHosts + {"http://good/image", emptyOptions, remoteHosts, nil, nil, nil, true}, + {"http://bad/image", emptyOptions, remoteHosts, nil, nil, nil, false}, // referrer - {"http://test/image", emptyOptions, nil, whitelist, nil, genRequest(map[string]string{"Referer": "http://good/foo"}), true}, - {"http://test/image", emptyOptions, nil, whitelist, nil, genRequest(map[string]string{"Referer": "http://bad/foo"}), false}, - {"http://test/image", emptyOptions, nil, whitelist, nil, genRequest(map[string]string{"Referer": "MALFORMED!!"}), false}, - {"http://test/image", emptyOptions, nil, whitelist, nil, genRequest(map[string]string{}), false}, + {"http://test/image", emptyOptions, nil, remoteHosts, nil, genRequest(map[string]string{"Referer": "http://good/foo"}), true}, + {"http://test/image", emptyOptions, nil, remoteHosts, nil, genRequest(map[string]string{"Referer": "http://bad/foo"}), false}, + {"http://test/image", emptyOptions, nil, remoteHosts, nil, genRequest(map[string]string{"Referer": "MALFORMED!!"}), false}, + {"http://test/image", emptyOptions, nil, remoteHosts, nil, genRequest(map[string]string{}), false}, // signature key {"http://test/image", Options{Signature: "NDx5zZHx7QfE8E-ijowRreq6CJJBZjwiRfOVk_mkfQQ="}, nil, nil, key, nil, true}, {"http://test/image", Options{Signature: "deadbeef"}, nil, nil, key, nil, false}, {"http://test/image", emptyOptions, nil, nil, key, nil, false}, - // whitelist and signature - {"http://good/image", emptyOptions, whitelist, nil, key, nil, true}, + // remoteHosts and signature + {"http://good/image", emptyOptions, remoteHosts, nil, key, nil, true}, {"http://bad/image", Options{Signature: "gWivrPhXBbsYEwpmWAKjbJEiAEgZwbXbltg95O2tgNI="}, nil, nil, key, nil, true}, - {"http://bad/image", emptyOptions, whitelist, nil, key, nil, false}, + {"http://bad/image", emptyOptions, remoteHosts, nil, key, nil, false}, } for _, tt := range tests { p := NewProxy(nil, nil) - p.Whitelist = tt.whitelist + p.RemoteHosts = tt.remoteHosts p.SignatureKey = tt.key p.Referrers = tt.referrers @@ -159,7 +159,7 @@ func TestAllowed(t *testing.T) { } func TestValidHost(t *testing.T) { - whitelist := []string{"a.test", "*.b.test", "*c.test"} + remoteHosts := []string{"a.test", "*.b.test", "*c.test"} tests := []struct { url string @@ -182,8 +182,8 @@ func TestValidHost(t *testing.T) { if err != nil { t.Errorf("error parsing url %q: %v", tt.url, err) } - if got, want := validHost(whitelist, u), tt.valid; got != want { - t.Errorf("validHost(%v, %q) returned %v, want %v", whitelist, u, got, want) + if got, want := validHost(remoteHosts, u), tt.valid; got != want { + t.Errorf("validHost(%v, %q) returned %v, want %v", remoteHosts, u, got, want) } } } @@ -326,7 +326,7 @@ func TestProxy_ServeHTTP(t *testing.T) { Client: &http.Client{ Transport: testTransport{}, }, - Whitelist: []string{"good.test"}, + RemoteHosts: []string{"good.test"}, ContentTypes: []string{"image/*"}, }