Skip to content

Endereço do visitante

Toda requisição que chega ao seu app passa antes pelo ingress do GoShip. Por isso o endereço da conexão que o app vê (o RemoteAddr do Go, o REMOTE_ADDR do PHP, o req.socket.remoteAddress do Node) é o do ingress, não o do visitante. O endereço do visitante vem nos cabeçalhos.

O que o GoShip garante

Em toda requisição, o GoShip define:

CabeçalhoValor
X-Real-IPo endereço que abriu a conexão com o GoShip
X-Forwarded-Foro mesmo endereço, sozinho
X-Forwarded-Protohttps ou http, como o visitante chegou
X-Forwarded-Hosto domínio pedido

Se o cliente mandar algum desses cabeçalhos, o valor dele é descartado e substituído. X-Forwarded-For não acumula o que veio antes: ele traz um endereço só. Assim, um visitante não consegue se passar por outro endereço só mandando um cabeçalho.

Vale no cluster GoShip e nos clusters que o GoShip monta nos seus servidores (Conectar servidor). Num Kubernetes que você conectou (Conectar Kubernetes), quem define esses cabeçalhos é o ingress do seu cluster.

Use X-Real-IP. Outros cabeçalhos que o cliente mandar, como True-Client-IP ou CF-Connecting-IP, chegam ao app como vieram. Não confie neles sem a verificação abaixo.

Com uma CDN na frente do seu domínio

Se o seu domínio próprio passa por uma CDN, como o proxy laranja da Cloudflare, quem abre a conexão com o GoShip é a CDN. Então X-Real-IP traz o endereço da CDN. O do visitante vem no cabeçalho da CDN: CF-Connecting-IP, no caso da Cloudflare.

Leia esse cabeçalho só quando X-Real-IP estiver nas faixas publicadas pela CDN. O endereço *.apps.goship.sh do app não passa pela CDN. Quem chamar esse endereço direto pode mandar o CF-Connecting-IP que quiser. A Cloudflare publica as faixas dela em https://www.cloudflare.com/ips/. Elas mudam pouco, mas mudam: atualize a lista de tempos em tempos.

Exemplo em Go:

package clientip

import (
	"net/http"
	"net/netip"
)

// Faixas de https://www.cloudflare.com/ips-v4 e https://www.cloudflare.com/ips-v6.
// Copie a lista completa e atualize de tempos em tempos.
var cloudflare = []netip.Prefix{
	netip.MustParsePrefix("173.245.48.0/20"),
	netip.MustParsePrefix("103.21.244.0/22"),
	// ...
	netip.MustParsePrefix("2606:4700::/32"),
}

// From devolve o endereço do visitante.
func From(r *http.Request) string {
	real := r.Header.Get("X-Real-IP") // definido pelo GoShip
	addr, err := netip.ParseAddr(real)
	if err != nil {
		return real
	}
	for _, p := range cloudflare {
		if p.Contains(addr.Unmap()) {
			if cf, err := netip.ParseAddr(r.Header.Get("CF-Connecting-IP")); err == nil {
				return cf.String()
			}
			break
		}
	}
	return real
}

O mesmo vale em qualquer linguagem: primeiro confira de onde veio a conexão (X-Real-IP), depois decida se o cabeçalho da CDN merece confiança.

Não adicione as faixas da CDN como “proxies confiáveis” num middleware que lê X-Forwarded-For de trás para frente. O GoShip já entrega um endereço só, então não há cadeia para percorrer.