GithubHelp home page GithubHelp logo

cactus / go-camo Goto Github PK

View Code? Open in Web Editor NEW
253.0 11.0 48.0 1.26 MB

A secure image proxy server

License: MIT License

Go 94.43% Makefile 5.19% Procfile 0.04% Dockerfile 0.35%
camo proxy-server image-proxy mixed-content-error mixed-content go golang golang-application

go-camo's Introduction

go-camo

About

go-camo is a go version of a camo server.

A camo server is a special type of image proxy that proxies non-secure images over SSL/TLS, in order to prevent mixed content warnings on secure pages. The server works in conjunction with back-end code that rewrites image URLs and signs them with an HMAC.

How it works

The general steps are as follows:

  • A client requests a page from the web app.

  • The original URL in the content is parsed.

  • An HMAC signature of the URL is generated.

  • The URL and hmac are encoded.

  • The encoded URL and hmac are placed into the expected format, creating the signed URL.

  • The signed URL replaces the original image URL.

  • The web app returns the content to the client.

  • The client requests the signed URL from Go-Camo.

  • Go-Camo validates the HMAC, decodes the URL, then requests the content from the origin server and streams it to the client.

  +----------+           request            +-------------+
  |          |----------------------------->|             |
  |          |                              |             |
  |          |                              |   web-app   |
  |          | img src=https://go-camo/url  |             |
  |          |<-----------------------------|             |
  |          |                              +-------------+
  |  client  |
  |          |     https://go-camo/url      +-------------+ http://some/img
  |          |----------------------------->|             |--------------->
  |          |                              |             |
  |          |                              |   go-camo   |
  |          |           img data           |             |    img data
  |          |<-----------------------------|             |<---------------
  |          |                              +-------------+
  +----------+

Go-Camo supports both hex and base64 encoded urls at the same time.

encoding tradeoffs

hex

longer, case insensitive, slightly faster

base64

shorter, case sensitive, slightly slower

Benchmark results with go1.12.7:

BenchmarkHexEncoder-4           	 1000000	      1364 ns/op
BenchmarkB64Encoder-4           	 1000000	      1447 ns/op
BenchmarkHexDecoder-4           	 1000000	      1312 ns/op
BenchmarkB64Decoder-4           	 1000000	      1379 ns/op

For examples of url generation, see the examples directory.

While Go-Camo will support proxying HTTPS images as well, for performance reasons you may choose to filter HTTPS requests out from proxying, and let the client simply fetch those as they are. The linked code examples do this.

Note that it is recommended to front Go-Camo with a CDN when possible.

Differences from Camo

  • Go-Camo supports 'Path Format' url format only. Camo’s "Query String Format" is not supported.

  • Go-Camo supports some optional "allow/deny" origin filters.

  • Go-Camo supports client http keep-alives.

  • Go-Camo provides native SSL support.

  • Go-Camo provides native HTTP/2 support

  • Go-Camo supports using more than one os thread (via GOMAXPROCS) without the need of multiple instances or additional proxying.

  • Go-Camo builds to a static binary. This makes deploying to large numbers of servers a snap.

  • Go-Camo supports both Hex and Base64 urls. Base64 urls are smaller, but case sensitive.

  • Go-Camo supports HTTP HEAD requests.

  • Go-Camo allows custom default headers to be added — useful for things like adding HSTS headers.

Installing pre-built binaries

Download the tarball appropriate for your OS/ARCH from binary releases.
Extract, and copy files to desired locations.

Building

Building requires:

  • make

  • posix compatible shell (sh)

  • git

  • go (most recent version recommended)

  • asciidoctor (for building man pages only)

Building:

# first clone the repo
$ git clone [email protected]:cactus/go-camo
$ cd go-camo

# show make targets
$ make
Available targets:
  help                this help
  clean               clean up
  all                 build binaries and man pages
  check               run checks and validators
  test                run tests
  cover               run tests with cover output
  build               build all binaries
  man                 build all man pages
  tar                 build release tarball
  cross-tar           cross compile and build release tarballs

# build all binaries (into ./bin/) and man pages (into ./man/)
# strips debug symbols by default
$ make all

# do not strip debug symbols
$ make all GOBUILD_LDFLAGS=""

Running

$ go-camo -k "somekey"
# run the gc less frequently (a bit better performance, uses more memory)
$ env GOGC=300 go-camo -k "somekey"

Go-Camo does not daemonize on its own. For production usage, it is recommended to launch in a process supervisor, and drop privileges as appropriate.

Examples of supervisors include: daemontools, runit, upstart, launchd, systemd, and many more.

For the reasoning behind lack of daemonization, see daemontools/why. In addition, the code is much simpler because of it.

Running on Heroku

In order to use this on Heroku with the provided Procfile, you need to:

Securing an installation

go-camo will generally do what you tell it to with regard to fetching signed urls. There is some limited support for trying to prevent dns rebinding attacks.

go-camo will attempt to reject any address matching an rfc1918 network block, or a private scope ipv6 address, be it in the url or via resulting hostname resolution.

Please note, however, that this does not provide protection for a network that uses public address space (ipv4 or ipv6), or some of the more exotic ipv6 addresses.

The list of networks rejected includes…​

Network Description

127.0.0.0/8

loopback

169.254.0.0/16

ipv4 link local

10.0.0.0/8

rfc1918

172.16.0.0/12

rfc1918

192.168.0.0/16

rfc1918

::1/128

ipv6 loopback

fe80::/10

ipv6 link local

fec0::/10

deprecated ipv6 site-local

fc00::/7

ipv6 ULA

::ffff:0:0/96

IPv4-mapped IPv6 address

More generally, it is recommended to either:

  • Run go-camo on an isolated instance (physical, vlans, firewall rules, etc).

  • Run a local resolver for go-camo that returns NXDOMAIN responses for addresses in deny-listed ranges (e.g. unbound’s private-address functionality). This is also useful to help prevent dns rebinding in general.

Configuring

Environment Vars

  • GOCAMO_HMAC - HMAC key to use.

  • HTTPS_PROXY - Configure an outbound proxy for HTTPS requests.
    Either a complete URL or a host[:port], in which case an HTTP scheme is assumed. See Upstream Http Proxying notes for more information.

  • HTTP_PROXY - Configure an outbound proxy for HTTP requests.
    Either a complete URL or a host[:port], in which case an HTTP scheme is assumed. See Upstream Http Proxying notes for more information.

Command line flags

$ go-camo -h
Usage: go-camo [flags]

An image proxy that proxies non-secure images over SSL/TLS

Flags:
  -h, --help                     Show context-sensitive help.
  -k, --key=STRING               HMAC key
  -H, --header=HEADER,...        Add additional header to each response.
                                 This option can be used multiple times to add
                                 multiple headers.
      --listen="0.0.0.0:8080"    Address:Port to bind to for HTTP
      --ssl-listen=HOST_PORT     Address:Port to bind to for HTTPS/SSL/TLS
      --socket-listen=PATH       Path for unix domain socket to bind to for HTTP
      --quic                     Enable http3/quic. Binds to the same port
                                 number as ssl-listen but udp+quic.
      --automaxprocs             Set GOMAXPROCS automatically to match Linux
                                 container CPU quota/limits.
      --ssl-key=PATH             ssl private key (key.pem) path
      --ssl-cert=PATH            ssl cert (cert.pem) path
      --max-size=INT             Max allowed response size (KB)
      --timeout=4s               Upstream request timeout
      --max-redirects=3          Maximum number of redirects to follow
      --max-size-redirect=URL    redirect to URL when max-size is exceeded
      --metrics                  Enable Prometheus compatible metrics endpoint
      --no-debug-vars            Disable the /debug/vars/ metrics endpoint.
                                 This option has no effects when the metrics are
                                 not enabled.
      --no-log-ts                Do not add a timestamp to logging
      --prof                     Enable go http profiler endpoint
      --log-json                 Log in JSON format
      --no-fk                    Disable frontend http keep-alive support
      --no-bk                    Disable backend http keep-alive support
      --allow-content-video      Additionally allow 'video/*' content
      --allow-content-audio      Additionally allow 'audio/*' content
      --allow-credential-urls    Allow urls to contain user/pass credentials
      --filter-ruleset=PATH      Text file containing filtering rules (one per
                                 line)
      --server-name="go-camo"    Value to use for the HTTP server field
      --expose-server-version    Include the server version in the HTTP server
                                 response header
      --enable-xfwd4             Enable x-forwarded-for passthrough/generation
  -v, --verbose                  Show verbose (debug) log level output
  -V, --version                  Print version and exit; specify twice to show
                                 license information.

A few notes about specific flags:

  • --filter-ruleset

    If a filter-ruleset file is defined, that file is read and each line is converted into a filter rule. See go-camo-filtering(5) for more information regarding the format for the filter file itself.

    Regarding evaluation: The ruleset is NOT evaluated in-order. The rules process in two phases: "allow rule phase" where the allow rules are evaluated, and the "deny rule phase" where the deny rules are evaluated. First match in each phase "wins" that phase.

    In the "allow phase", an origin request must match at least one allow rule. The first rule to match "wins" and the request moves on to the next phase. If there are no allow rules supplied, this phase is skipped.

    In the deny rule phase, any rule that matches results in a rejection. The first match "wins" and the request is failed. If there are no deny rules supplied, this phase is skipped.

    💡

    It is always preferable to do filtering at the point of URL generation and signing. The filter-ruleset functionality (both allow and deny) is supplied predominantly as a fallback safety measure, for cases where you have previously generated a URL and you need a quick temporary fix, or where rolling keys takes a while and/or is difficult.

  • --max-size

    The --max-size value is defined in KB. Set to 0 to disable size restriction. The default is 0.

  • --metrics

    If the metrics flag is provided, then the service will expose a Prometheus /metrics endpoint and a /debug/vars endpoint from the go expvar package.

  • --no-debug-vars

    If the no-debug-vars flag is provided along with the metrics flag, the /debug/vars endpoint is removed.

  • -k, --key

    If the HMAC key is provided on the command line, it will override (if present), an HMAC key set in the environment var.

  • -H, --header

    Additional default headers (sent on every response) can also be set. This argument may be specified many times.

    The list of default headers sent are:

    X-Content-Type-Options: nosniff
    X-XSS-Protection: 1; mode=block
    Content-Security-Policy: default-src 'none'; img-src data:; style-src 'unsafe-inline'

    As an example, if you wanted to return a Strict-Transport-Security header by default, you could add this to the command line:

    -H "Strict-Transport-Security: max-age=16070400"
  • --allow-content-video and --allow-content-audio

    By default only image/* content-types are accepted and proxied, all other content-types are rejected.

    Add the --allow-content-video argument to addtionally allow video/* content types.

    Add the --allow-content-audio argument to addtionally allow audio/* content types.

Upstream Http Proxying

Care should be taken when using upstream http proxy support. go-camo has several protections against SSRF vectors, for example:

  • Checking http redirect chains against rfc1918 addresses.

  • Limits to maximum number of redirects.

  • Protection against self-redirect loops.

  • Various other protections.

The use of an upstream http proxy may subvert several of these protections, as go-camo will be required to offload certain operations to the upstream http proxy.

Some examples (list is not exhaustive):

  • The upstream http proxy itself may be responsible for following redirects (depending on configuration). As such, go-camo may not have visibility into the redirect chain. This could result in resource exhaustion (redirect loops), or SSRF (redirects to internal URLs).

  • The upstream http proxy itself will be responsible for connecting to external servers, and would need to be configured for any request size limits. While go-camo would still limit request sizes based on its own configuration, the upstream http proxy may still fetch the content before handoff.

  • There may be other chances for "configuration confusion" — where two services are configured together in such a way, that introduces issues not possible when operating standalone.

Proper configuration of the upstream http proxy may mitigate these issues.
Test your configurations and monitor carefully!

Monitoring

Metrics

When the --metrics flag is used, the service will expose a Prometheus-compatible /metrics endpoint. This can be used by monitoring systems to gather data.

The endpoint includes all of the default go_ and process_. In addition, a number of custom metrics.

Name Type Help

camo_response_duration_seconds

Histogram

A histogram of latencies for proxy responses.

camo_response_size_bytes

Histogram

A histogram of sizes for proxy responses.

camo_proxy_content_length_exceeded_total

Counter

The number of requests where the content length was exceeded.

camo_proxy_reponses_failed_total

Counter

The number of responses that failed to send to the client.

camo_proxy_reponses_truncated_total

Counter

The number of responses that were too large to send.

camo_responses_total

Counter

Total HTTP requests processed by the go-camo, excluding scrapes.

It also includes a camo_build_info metric that exposes the version. In addition, you can expose some extra data to metrics via env vars, if desired:

  • Revision via APP_INFO_REVISION

  • Branch via APP_INFO_BRANCH

  • BuildDate via APP_INFO_BUILD_DATE

  • You can also override the version by setting APP_INFO_VERSION

A /debug/vars endpoint is also included with --metrics by default. This endpoint returns memstats and some additional data. This endpoint can be disabled by additionally supplying the --no-debug-vars flag.

Additional tools

Go-Camo includes a couple of additional tools.

url-tool

The url-tool utility provides a simple way to generate signed URLs from the command line.

$ url-tool -h
Usage:
  url-tool [OPTIONS] <decode | encode>

Application Options:
  -k, --key=    HMAC key
  -p, --prefix= Optional URL prefix used by encode output

Help Options:
  -h, --help    Show this help message

Available commands:
  decode  Decode a URL and print result
  encode  Encode a URL and print result

Example usage:

# hex
$ url-tool -k "test" encode -p "https://img.example.org" "http://golang.org/doc/gopher/frontpage.png"
https://img.example.org/0f6def1cb147b0e84f39cbddc5ea10c80253a6f3/687474703a2f2f676f6c616e672e6f72672f646f632f676f706865722f66726f6e74706167652e706e67

$ url-tool -k "test" decode "https://img.example.org/0f6def1cb147b0e84f39cbddc5ea10c80253a6f3/687474703a2f2f676f6c616e672e6f72672f646f632f676f706865722f66726f6e74706167652e706e67"
http://golang.org/doc/gopher/frontpage.png

# base64
$ url-tool -k "test" encode -b base64 -p "https://img.example.org" "http://golang.org/doc/gopher/frontpage.png"
https://img.example.org/D23vHLFHsOhPOcvdxeoQyAJTpvM/aHR0cDovL2dvbGFuZy5vcmcvZG9jL2dvcGhlci9mcm9udHBhZ2UucG5n

$ url-tool -k "test" decode "https://img.example.org/D23vHLFHsOhPOcvdxeoQyAJTpvM/aHR0cDovL2dvbGFuZy5vcmcvZG9jL2dvcGhlci9mcm9udHBhZ2UucG5n"
http://golang.org/doc/gopher/frontpage.png

Containers

There are containers built automatically from version tags, pushed to both docker hub and github packages.

These containers are untested and provided only for those with specific containerization requirements. When in doubt, prefer the statically compiled binary releases, unless you specifically need a container.

Changelog

See CHANGELOG.

License

Released under the MIT license. See LICENSE file for details.

go-camo's People

Contributors

alexmv avatar alexzeitgeist avatar craigmiskell-gitlab avatar dee-see avatar dependabot[bot] avatar digitalmoksha avatar dropwhile avatar ewdurbin avatar grosskur avatar igorwwwwwwwwwwwwwwwwwwww avatar jacobbednarz avatar jdreesen avatar jessehall3 avatar mitch354 avatar mrsaints avatar pataquets avatar r38y avatar superq avatar vaibhav-009 avatar vinay0508 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

go-camo's Issues

Debian + php

Hello,

Can your solution run on a dedicated Debian-based server? A script in php is it easy to write?
If possible, do you think you can help me?
This is to replace the atmos/camo solution

Thank you in advance

Add option to disable /debug/vars endpoint

Specifications

There's a /debug/vars which dumps a bunch of information about the running process. It would be great if we could disable this with a command-line option. I had a quick look to open a PR but it wasn't obvious to me how this is done. If you have any pointers I'm happy to open the PR myself.

Expected Behavior

A new command-line option to disable /debug/vars. I think it should be disabled by default but I understand it would be a breaking change.

Actual Behavior

/debug/vars cannot be disabled

Steps to reproduce

Start camo and visit /debug/vars

Allow use with non-image files?

Is there a particular reason this is limited to image files? I am using it on a service where I also proxy video files. It was easiest for me to disable the check for the image header and allow anything through. It might be nice if this was a config option to either allow proxying anything, or lock down by type.

Video content not supported in Safari

Specifications

Version: go-camo 1.1.4-9-g4369d52 (go1.12.4,gc-amd64)
Platform: macOS 10.14.5

Expected Behavior

Visiting a proxied video in Safari should display properly

Actual Behavior

The video does not display, we always get a write: broken pipe. Here is the log output:

time="2019-07-24T18:26:07.030372000-05:00" level="D" msg="client request" req="&{GET /694bea43b037fdf93ef5efc6c9ab6c2fe7f2ba2f/687474703a2f2f636c6970732e766f727761657274732d676d62682e64652f6269675f6275636b5f62756e6e792e6d7034 HTTP/1.1 1 1 map[Accept:[text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8] Accept-Encoding:[gzip, deflate] Accept-Language:[en-us] Connection:[keep-alive] Upgrade-Insecure-Requests:[1] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15]] {} <nil> 0 [] false localhost:8080 map[] map[] <nil> map[] [::1]:61038 /694bea43b037fdf93ef5efc6c9ab6c2fe7f2ba2f/687474703a2f2f636c6970732e766f727761657274732d676d62682e64652f6269675f6275636b5f62756e6e792e6d7034 <nil> <nil> <nil> 0xc000192ec0}"

time="2019-07-24T18:26:07.030477000-05:00" level="D" msg="signed client url" url="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"

time="2019-07-24T18:26:07.067896000-05:00" level="D" msg="built outgoing request" req="&{GET http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 HTTP/1.1 1 1 map[Accept:[image/*, video/*] Accept-Language:[en-us] User-Agent:[go-camo] Via:[go-camo]] <nil> <nil> 0 [] false clips.vorwaerts-gmbh.de map[] map[] <nil> map[]   <nil> <nil> <nil> <nil>}"

time="2019-07-24T18:26:07.161521000-05:00" level="D" msg="response from upstream" resp="&{200 OK 200 HTTP/1.1 1 1 map[Accept-Ranges:[bytes] Age:[15970] Cache-Control:[public, max-age=31536000] Cf-Cache-Status:[HIT] Cf-Ray:[4fb9a83eadcc5847-DFW] Connection:[keep-alive] Content-Length:[5510872] Content-Type:[video/mp4] Date:[Wed, 24 Jul 2019 23:26:07 GMT] Etag:[\"5416d8-47f21fa7d3300\"] Expires:[Thu, 23 Jul 2020 23:26:07 GMT] Last-Modified:[Tue, 09 Feb 2010 02:50:20 GMT] Server:[cloudflare] Set-Cookie:[__cfduid=d49c393732047191c856d72870210062c1564010767; expires=Thu, 23-Jul-20 23:26:07 GMT; path=/; domain=.vorwaerts-gmbh.de; HttpOnly]] 0xc0001336a0 5510872 [] false false map[] 0xc000195600 <nil>}"

time="2019-07-24T18:26:07.240210000-05:00" level="D" msg="error writing response" err="write tcp [::1]:8080->[::1]:61038: write: broken pipe"

time="2019-07-24T18:26:07.319530000-05:00" level="D" msg="client request" req="&{GET /694bea43b037fdf93ef5efc6c9ab6c2fe7f2ba2f/687474703a2f2f636c6970732e766f727761657274732d676d62682e64652f6269675f6275636b5f62756e6e792e6d7034 HTTP/1.1 1 1 map[Accept:[*/*] Accept-Encoding:[identity] Accept-Language:[en-us] Connection:[keep-alive] Range:[bytes=0-1] Referer:[http://localhost:8080/694bea43b037fdf93ef5efc6c9ab6c2fe7f2ba2f/687474703a2f2f636c6970732e766f727761657274732d676d62682e64652f6269675f6275636b5f62756e6e792e6d7034] User-Agent:[Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_5) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.1.1 Safari/605.1.15] X-Playback-Session-Id:[DB7C49DD-C663-4A25-8E83-B309A6B59029]] {} <nil> 0 [] false localhost:8080 map[] map[] <nil> map[] [::1]:61043 /694bea43b037fdf93ef5efc6c9ab6c2fe7f2ba2f/687474703a2f2f636c6970732e766f727761657274732d676d62682e64652f6269675f6275636b5f62756e6e792e6d7034 <nil> <nil> <nil> 0xc00025e880}"

time="2019-07-24T18:26:07.319626000-05:00" level="D" msg="signed client url" url="http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4"

time="2019-07-24T18:26:07.359092000-05:00" level="D" msg="built outgoing request" req="&{GET http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4 HTTP/1.1 1 1 map[Accept:[image/*, video/*] Accept-Language:[en-us] User-Agent:[go-camo] Via:[go-camo]] <nil> <nil> 0 [] false clips.vorwaerts-gmbh.de map[] map[] <nil> map[]   <nil> <nil> <nil> <nil>}"

time="2019-07-24T18:26:07.454661000-05:00" level="D" msg="response from upstream" resp="&{200 OK 200 HTTP/1.1 1 1 map[Accept-Ranges:[bytes] Age:[15970] Cache-Control:[public, max-age=31536000] Cf-Cache-Status:[HIT] Cf-Ray:[4fb9a8408948d266-DFW] Connection:[keep-alive] Content-Length:[5510872] Content-Type:[video/mp4] Date:[Wed, 24 Jul 2019 23:26:07 GMT] Etag:[\"5416d8-47f21fa7d3300\"] Expires:[Thu, 23 Jul 2020 23:26:07 GMT] Last-Modified:[Tue, 09 Feb 2010 02:50:20 GMT] Server:[cloudflare] Set-Cookie:[__cfduid=dfe12ec4a2315005f34afeb93d96682491564010767; expires=Thu, 23-Jul-20 23:26:07 GMT; path=/; domain=.vorwaerts-gmbh.de; HttpOnly]] 0xc000133b00 5510872 [] false false map[] 0xc000195900 <nil>}"

time="2019-07-24T18:26:07.458221000-05:00" level="D" msg="error writing response" err="write tcp [::1]:8080->[::1]:61043: write: broken pipe"

Steps to reproduce

Visit a proxied URL, such as http://mirrors.standaloneinstaller.com/video-sample/small.mp4. Safari will be unable to show the video. Chrome and Firefox can (as long as the -H "Content-Security-Policy: media-src 'self'" option is used).

The problem seems to stem from Safari requiring support for byte ranges. You can take a look at Configuring Your Server. This talks about iOS but it's the same for safari on macOS.

I'm able to get it working by adding

	"Accept-Ranges":    true,
	"Content-Length": true,
	"Content-Range":  true,

to ValidRespHeaders and

	"Range": true,

to ValidReqHeaders.

We also have to allow the 206 status code.

I'll try to get a PR submitted, though my Go skills are minimal right now.

Please implement caching

Someone, please tell me why on Earth Camo decides to fetch the same effing file 30 times (and counting, I should say!) in the matter of just 43 seconds?

15/Feb/2017:09:12:10 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	#go-camo
15/Feb/2017:09:12:11 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:12 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:13 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:14 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:15 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:17 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:18 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:19 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:20 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:21 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:27 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:28 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:29 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:30 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:30 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:32 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:33 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:34 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:35 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:37 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:38 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:39 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:41 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:42 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:45 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:46 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:50 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:51 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo
15/Feb/2017:09:12:53 +0100	176.9.43.119	https://${hostname}/0d61156a-f0a4-5383-9ae8-b72430f3fa50.png	GET HTTP/1.1 200 92320	go-camo

Ever heard about If-Modified-Since? Or Etag?

Seriously guys, please implement some caching!

Eventually stops working

Hi again! Performance is great, but occasionally the server will just stop serving images, giving "Error Fetching Resource" errors. RAM usage also seems to increase gradually in this state. Restarting the server fixes it, and this only happens after 12-24 hours of serving:

ClientsServed, BytesServed
825656, 28116134997

Here's the information I gathered:

Console output before I restarted https://gist.github.com/586b121c3fba40d8796b
Memory usage vs traffic throughput: http://puu.sh/968Og/f48ce431fb.png
Response headers of a failed request in this state: http://puu.sh/968QM/e0fb98fece.png

Docker ARM64 image

As of the spread of ARM64 cloud services I think that making the docker image ARM64 compatible would be a great addition.

Heroku deployment failure.

Has anyone tried to deploy this to Heroku recently? I followed the steps in the Readme but it didn't deploy cleanly.

remote: -----> Installing go1.9.2
remote: -----> Fetching go1.9.2.linux-amd64.tar.gz... done
remote: -----> Fetching errors-0.8.0.tar.gz... done
remote: -----> Fetching gb-0.4.4.tar.gz... done
remote: -----> Installing GB v0.4.4... done
remote: -----> Running: gb build -tags heroku
remote: FATAL: command "build" failed: failed to resolve import path "go-camo": import "github.com/cactus/mlog": not found: stat /tmp/build_88ee5abdb34d81f2c8b95e589722bb0f/src/github.com/cactus/mlog: no such file or directory
remote:  !     Push rejected, failed to compile Go app.
remote:
remote:  !     Push failed
remote: Verifying deploy...
remote:
remote: !    Push rejected to usercontent-go.
remote:

PS. I'm not a Go-pher but want to switch to using this over the Node version.

Not adding 'margin: 0px' style to HTML body

I've noticed with GitHub's and other language implementations of Camo, as well as direct linking images, it sets the body style to 'margin: 0px'. With my go-camo setup however it does not. This obviously is not a big deal but it might cause some weird behaviour.

Imgur image:

<html>

<head>
    <meta name="viewport" content="width=device-width, minimum-scale=0.1">
    <title>fPlzJcC.png (1920×1200)</title>
</head>

<body style="margin: 0px;" cz-shortcut-listen="true"><img style="user-select: none; cursor: zoom-in;" src="https://i.imgur.com/fPlzJcC.png" width="1362" height="851"></body>

</html>

go-camo image:

<html>

<head>
    <meta name="viewport" content="width=device-width, minimum-scale=0.1">
    <title>687474703a2f2f692e696d6775722e636f6d2f66506c7a4a63432e706e67 (1920×1200)</title>
</head>

<body cz-shortcut-listen="true"><img style="cursor: zoom-in;" src="https://camo.buttwaters.com/f395cd45c27220bc64cd770e97a1f36bbc3a5418/687474703a2f2f692e696d6775722e636f6d2f66506c7a4a63432e706e67" width="1362" height="851"></body>

</html>

As you can see by navigating to those links, the Camo version has a small margin to the left and top of the image, and I haven't seen something like this anywhere else.

It's also probably worth noting that it throws these errors to the HTTP console, which I'm not sure what to do about:

687474703a2f2f692e696d6775722e636f6d2f66506c7a4a63432e706e67:1 Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'none'". Either the 'unsafe-inline' keyword, a hash ('sha256-H/s/dWGkGDaCkKqmo0VNeHrTgvJjinI5uvu7UmY6EB8='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.

687474703a2f2f692e696d6775722e636f6d2f66506c7a4a63432e706e67:1 Refused to apply inline style because it violates the following Content Security Policy directive: "default-src 'none'". Either the 'unsafe-inline' keyword, a hash ('sha256-15TqmL1cbLqMXH1nK4EwD191NLSXxlbnYzFAfbG/xp8='), or a nonce ('nonce-...') is required to enable inline execution. Note also that 'style-src' was not explicitly set, so 'default-src' is used as a fallback.

687474703a2f2f692e696d6775722e636f6d2f66506c7a4a63432e706e67:1 Refused to load the image 'https://camo.buttwaters.com/favicon.ico' because it violates the following Content Security Policy directive: "default-src 'none'". Note that 'img-src' was not explicitly set, so 'default-src' is used as a fallback.

Responsible Vulnerability Disclosure

Specifications

Version: go-camo 1.1.4
Platform: Any

Behavior

I would like to report a security vulnerability in go-camo. Is there a prefered (and confidentially) way of receiving more details?

build failed with incorrect import?

can't load package: package github.com/cactus/go-camo/cmd/go-camo: code in directory /go/src/github.com/cactus/go-camo/cmd/go-camo expects import "github.com/cactus/go-camo"
can't load package: package github.com/cactus/go-camo/cmd/url-tool: code in directory /go/src/github.com/cactus/go-camo/cmd/url-tool expects import "github.com/cactus/go-camo"

I think the directory structure is changed, but not the import path hint.

Ignore `Content-Type` of redirects

Specifications

Please list the go-camo version, as well as the Operation System (and version) that go-camo is running on. The go-camo version can be found by go-camo -V.

Version: v2.4.3 (we are actually running a fork, though: https://github.com/pypi/camo)
Platform: Linux

Expected Behavior

go-camo does not consider the Content-Type of redirects as it follows the redirects, only the Content-Type of the final response. Since it's a bit ambiguous what a valid Content-Type for a redirect is, go-camo should not error out based on the Content-Type of a redirect response.

Actual Behavior

The application returns a 404 Not Found as soon as it encounters a redirect response with a non-image Content-Type.

Steps to reproduce

I don't have an example online to try this against anymore (because the image hosting service which produced this behavior has since been updated to return a different Content-Type) but this could be reproduced with a simple HTTP service that responds with a 30x redirect and sets the Content-Type header to something like application/json.

Connection to an internal proxy does not work

Specifications

Please list the go-camo version, as well as the Operation System (and version)
that go-camo is running on. The go-camo version can be found by go-camo -V.

Version: 2.3.0
Platform: Ubuntu 20.04 Container

Expected Behavior

When a proxy is configured and it normally (enterprise environment) has an internal ip, camo should be able to connect to the proxy.

Actual Behavior

from the log:

time="2022-01-13T08:27:36.137103866Z" level="D" msg="ip filter rejection from dial.control" err="Get \"someUrl\": proxyconnect tcp: dial tcp [::1]:4750: ip rejection"

In the case above a proxy on localhost is used.

Steps to reproduce

Configure camo to use a proxy with a private ip.

Deny hosts resolving to rfc1918 addresses

I had this log entry today:

2017/01/15 05:46:49 [error] 8403#8403: *73363 access forbidden by rule, client: 127.0.0.1, server: _, request: "GET /cnwk.1d/i/bto/20090806/iRex_DR800_mock.png HTTP/1.1", host: "i.i.com.com"

http://i.i.com.com/cnwk.1d/i/bto/20090806/iRex_DR800_mock.png used to point to an image; nowadays though, the host resolves to 127.0.0.1. Yet go-camo dutifully attempts to request the URL. This could potentially leak private information if there's a private server listening on 127.0.0.1.

I suggest to resolve a domain first before making the proxy request and deny it if the domain resolves to an rfc1918 address.

Publish Docker image

Feature Proposal

It would be useful to have an official image on Docker that we can use to deploy go-camo.

runtime error: slice bounds out of range

Running under some degree of load (30-40mbit) I occasionally get the following error. I believe after some period this affects the server's ability to process requests at all. It seems like it could be a go-level issue, and on reading up it may be related to keepalives. I'll try some other options, but here is the exception for the time being:

2014/05/26 14:03:20 http: panic serving 141.101.96.59:21920: runtime error: slice bounds out of range
goroutine 437 [running]:
net/http.func·009()
        /usr/lib/go/src/pkg/net/http/server.go:1093 +0xae
runtime.panic(0x657800, 0x95af4a)
        /usr/lib/go/src/pkg/runtime/panic.c:248 +0x106
github.com/cactus/go-camo/camo.(*Proxy).ServeHTTP(0xc210051400, 0x7fa83d0c9720, 0xc210623000, 0xc2105e1a90)
        /root/go-camo/build/src/github.com/cactus/go-camo/camo/proxy.go:196 +0x1b25
github.com/gorilla/mux.(*Router).ServeHTTP(0xc21000a550, 0x7fa83d0c9720, 0xc210623000, 0xc2105e1a90)
        /root/go-camo/build/src/github.com/gorilla/mux/mux.go:98 +0x217
net/http.(*ServeMux).ServeHTTP(0xc2100376c0, 0x7fa83d0c9720, 0xc210623000, 0xc2105e1a90)
        /usr/lib/go/src/pkg/net/http/server.go:1496 +0x163
net/http.serverHandler.ServeHTTP(0xc21000a1e0, 0x7fa83d0c9720, 0xc210623000, 0xc2105e1a90)
        /usr/lib/go/src/pkg/net/http/server.go:1597 +0x16e
net/http.(*conn).serve(0xc2105f7180)
        /usr/lib/go/src/pkg/net/http/server.go:1167 +0x7b7
created by net/http.(*Server).Serve
        /usr/lib/go/src/pkg/net/http/server.go:1644 +0x28b

Running with fairly basic options:
go-camo --max-size=2048 --listen=:80 -k <key>

Build instructions not complete

Specifications

Please list the go-camo version, as well as the Operation System (and version)
that go-camo is running on. The go-camo version can be found by go-camo -V.

Version: git master
Platform: macos 10.13

Expected Behavior

go-camo compiles

Actual Behavior

package github.com/cactus/go-camo: no Go files in /tmp/go/src/github.com/cactus/go-camo

Steps to reproduce

Follow the README instructions:

➜  ~ export GOPATH=/tmp/go
➜  ~ go get -d github.com/cactus/go-camo
package github.com/cactus/go-camo: no Go files in /tmp/go/src/github.com/cactus/go-camo

Handling Cloudflare Challenges with go-camo

Specifications

Version: 2.4.3-2-ga397323
Platform: Debian Buster

Expected Behavior

Many sites use Cloudflare, which can "challenge" outgoing requests from go-camo, causing issues. Ideally, we could use fallback servers with go-camo to retry these challenged requests. Often, Cloudflare challenges occur when the go-camo server IP is temporarily "blacklisted". If go-camo could pass the request to another instance on a different server with a different IP, it's more likely to avoid blacklisting and pass through Cloudflare unchallenged.

Actual Behavior

As an example, here, the image https://www.globus.ch/cf-media/akeneo/2000402238436_FP_PNG_1/1680537905/1200.png was requested; Cloudflare "challenged" the request (Cf-Mitigated: challenge, see https://developers.cloudflare.com/fundamentals/get-started/concepts/cloudflare-challenges/#detecting-a-challenge-page-response).

Jun 06 08:18:09 proxy-host go-camo-netgo[16037]: time="2023-06-06T08:18:09.303956624-04:00" level="D" msg="signed client url" url="URL https://www.globus.ch/cf-media/akeneo/2000402238436_FP_PNG_1/1680537905/1200.png was requested."
Jun 06 08:18:09 proxy-host go-camo-netgo[16037]: time="2023-06-06T08:18:09.307941800-04:00" level="D" msg="built outgoing request" req="content_length=\"0\" transfer_encoding=\"[]\" host=\"www.globus.ch\" remote_addr=\"\" method=\"GET\" path=\"\" proto=\"HTTP/1.1\" header=\"map[Accept:[image/*] Accept-Language:[en-US,en;q=0.9,de;q=0.8] Cache-Control:[no-cache] User-Agent:[Camo Asset Proxy] Via:[Camo Asset Proxy]]\""
Jun 06 08:18:09 proxy-host go-camo-netgo[16037]: time="2023-06-06T08:18:09.358322679-04:00" level="D" msg="response from upstream" content_length="-1" header="map[Alt-Svc:[h3=\":443\"; ma=86400] Cache-Control:[private, max-age=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0] Cf-Mitigated:[challenge] Cf-Ray:[7d3098a84c5600a8-CDG]Content-Type:[text/html; charset=UTF-8] Cross-Origin-Embedder-Policy:[require-corp] Cross-Origin-Opener-Policy:[same-origin] Cross-Origin-Resource-Policy:[same-origin] Date:[Tue, 06 Jun 2023 12:18:09 GMT] Expires:[Thu, 01 Jan 1970 00:00:01 GMT] Permissions-Policy:[accelerometer=(),autoplay=(),camera=(),clipboard-read=(),clipboard-write=(),fullscreen=(),geolocation=(),gyroscope=(),hid=(),interest-cohort=(),magnetometer=(),microphone=(),payment=(),publickey-credentials-get=(),screen-wake-lock=(),serial=(),sync-xhr=(),usb=()] Referrer-Policy:[same-origin] Server:[cloudflare] Strict-Transport-Security:[max-age=15552000; preload] X-Frame-Options:[SAMEORIGIN]]" proto="HTTP/1.1" status="403" transfer_encoding="[chunked]"

As a result, go-camo isn't able to proxy the image.

runtime error: invalid memory address or nil pointer dereference

On b2fd2b1:

2014/05/26 23:36:12 http: panic serving 173.245.51.193:53188: runtime error: invalid memory address or nil pointer dereference
goroutine 5495 [running]:
net/http.func·009()
        /usr/lib/go/src/pkg/net/http/server.go:1093 +0xae
runtime.panic(0x657800, 0x95ad48)
        /usr/lib/go/src/pkg/runtime/panic.c:248 +0x106
github.com/cactus/go-camo/camo.(*Proxy).ServeHTTP(0xc2100523c0, 0x7fce2bb17848, 0xc211196a00, 0xc210dbf000)
        /root/go-camo/build/src/github.com/cactus/go-camo/camo/proxy.go:237 +0x1741
github.com/gorilla/mux.(*Router).ServeHTTP(0xc21001fa00, 0x7fce2bb17848, 0xc211196a00, 0xc210dbf000)
        /root/go-camo/build/src/github.com/gorilla/mux/mux.go:98 +0x217
net/http.(*ServeMux).ServeHTTP(0xc2100386c0, 0x7fce2bb17848, 0xc211196a00, 0xc210dbf000)
        /usr/lib/go/src/pkg/net/http/server.go:1496 +0x163
net/http.serverHandler.ServeHTTP(0xc21001fc30, 0x7fce2bb17848, 0xc211196a00, 0xc210dbf000)
        /usr/lib/go/src/pkg/net/http/server.go:1597 +0x16e
net/http.(*conn).serve(0xc210a55d00)
        /usr/lib/go/src/pkg/net/http/server.go:1167 +0x7b7
created by net/http.(*Server).Serve
        /usr/lib/go/src/pkg/net/http/server.go:1644 +0x28b

Feature Suggestion: MP4 Support

Specifications

Go-camo from the Docker Hub (tagged v2.4.13) seems to be failing to proxy MP4 content. I use it in conjunction with a custom version of akkoma, where I modified the code to output go-camo URL format (by default it created HMAC on the base64 encoded URL, I simply made it sign the URL before base64 encoding).

Right now I am forced to implement a hacky workaround in nginx configs, where if the file ends with "mp4" I let akkoma's built-in media proxy handle it, and if not, go-camo handles it. The reason for using go-camo instead of akkoma's built-in media proxy to begin with is performance, built-in proxy takes upward to 30 seconds to load an external image, while go-camo does so under one second, due to the round trip involved in my setup (with akkoma media proxy, it's browser -> webserver -> appserver -> webserver -> browser, while with go-camo it's merely browser -> webserver -> browser as I can let go-camo simply run on the webserver, each -> signifies a connection to a different server over the internet).

Version: v2.4.13
Platform: Docker (Debian Bookworm host, kernel 6.1 series)

Expected Behavior

MP4 file is proxied.

Actual Behavior

Go-camo outputs "Unsupported content-type returned."

Steps to reproduce

  1. Attempt to proxy MP4 content
  2. Observe the error

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.