Wiki
GeoIP e controlo de acesso geográfico
Como o QuoteNode usa uma base de dados GeoIP local para controlo de acesso por país e seguimento de propostas.
GeoIP e controlo de acesso geográfico
O QuoteNode inclui um controlo de acesso geográfico opcional e seguimento por país através de uma base de dados GeoIP local por país (DB-IP Country Lite sem chave por predefinição, ou MaxMind GeoLite2).
Dois usos do GeoIP
1. Controlo de acesso à aplicação
Quando ativado, o filtro GeoIP pode restringir o acesso à aplicação a determinados países. Os pedidos de países não permitidos recebem HTTP 403 (Forbidden).
É útil para organizações que:
- operam apenas em jurisdições específicas,
- querem reduzir a exposição a ataques automatizados de certas regiões,
- têm de cumprir requisitos de residência de dados ou de controlo de acesso.
2. Seguimento de interações com a proposta
Quando um cliente abre um link público de proposta, o sistema regista o código do país do cliente (ISO 3166-1 alpha-2) juntamente com o evento de interação. Isto dá contexto geográfico à análise de propostas:
- «A sua proposta foi aberta a partir da Alemanha» — confirma alcance internacional,
- «Várias aberturas de países diferentes» — pode indicar que a proposta foi reencaminhada.
Como funciona
Base de dados
A resolução GeoIP usa uma base de dados local por país no formato MaxMind DB (.mmdb) — não uma API externa. Todas as consultas ocorrem em memória, sem chamadas de rede.
Por predefinição é a edição DB-IP Country Lite sem chave (licença CC-BY-4.0, sem conta). O contentor descarrega-a automaticamente no arranque (e segundo um agendamento diário) se estiver em falta ou desatualizada — independentemente de GEOIP_ENABLED, governado por GEOIP_AUTO_UPDATE (predefinição true). A base pode assim estar pronta enquanto a imposição por país está desligada. Sem descarga manual nem montagem de ficheiro. Para usar antes o MaxMind GeoLite2, define MAXMIND_ACCOUNT_ID / MAXMIND_LICENSE_KEY (uma conta MaxMind gratuita); é o mesmo formato .mmdb. Também podes preencher o ficheiro manualmente com scripts/update-geoip.sh.
Deteção do IP
O IP do cliente é resolvido inteiramente pela aplicação — não é retirado cegamente dos cabeçalhos do pedido. Um X-Forwarded-For, X-Real-IP ou CF-Connecting-IP falsificado a partir de um cliente direto nunca pode falsificar a verificação de país.
- A aplicação toma o par de transporte (o endereço que efetivamente abriu a ligação).
- Se esse par não for interno, todos os cabeçalhos de reencaminhamento são ignorados e o par é usado diretamente. Um par é interno quando é um proxy de confiança explícito ou qualquer endereço não roteável globalmente (privado/RFC 1918, loopback, link-local, CGNAT, IPv6 ULA) — que, atrás de Docker/Coolify, é sempre interno ao contentor.
- Se o par for interno, o cliente é derivado dos seus metadados de reencaminhamento por ordem:
CF-Connecting-IP(para que um CDN como a Cloudflare que reescreveX-Forwarded-Forcontinue a dar o cliente real) →X-Forwarded-For(percorrido da direita para a esquerda, ignorando saltos internos) →X-Real-IP. Apenas são aceites IP literais (sem DNS).
Como os pares privados e os CDN são tratados automaticamente, a maioria das implantações não precisa de configuração — o Caddy integrado, uma edge Coolify ou um CDN à frente funcionam de imediato. A variável opcional SECURITY_TRUSTED_PROXIES (IP/CIDR literais separados por vírgulas e/ou nomes de host de serviço) só acrescenta confiança para um proxy invulgar cujo par de transporte seja um endereço público.
O IP do cliente é um filtro grosseiro de melhor esforço, não autenticação. Quem conseguir alcançar a origem diretamente (contornando o CDN/proxy) poderia apresentar um
CF-Connecting-IPà escolha; o reforço recomendado é restringir a origem por firewall para que apenas o seu CDN/proxy a alcance.
Os endereços de cliente não roteáveis globalmente (loopback, privados/RFC 1918, link-local, CGNAT, IPv6 ULA) nunca são geo-bloqueados — não podem ser geolocalizados — pelo que os health checks de localhost e os deployments LAN/same-host continuam a funcionar enquanto o GeoIP está ativo. A lista de permissões de IP e a autenticação continuam a aplicar-se-lhes.
Caminhos isentos
Os seguintes caminhos estão sempre isentos das restrições geográficas para se manterem acessíveis em todo o mundo:
- links públicos de propostas (
/offer/public/*) e branding público (/api/v1/public/branding/*), - ações de links de e-mail: cancelamento de subscrição (
/api/v1/notifications/unsubscribe-token/*) e preferências públicas (/api/v1/notifications/preferences-public/*), - endpoints de infraestrutura/saúde (
/health*,/actuator/health,/actuator/info).
A autenticação de administrador (/api/v1/auth/login, 2FA) e os recursos autenticados continuam sujeitos ao controlo geográfico.
Configuração
| Variável | Por omissão | Descrição |
|---|---|---|
GEOIP_ENABLED |
false |
Apenas interruptor de imposição por país — também o interruptor de emergência. Não afeta o carregamento da base de dados: a BD continua a carregar e a atualizar-se (ver GEOIP_AUTO_UPDATE), por isso pode estar pronta enquanto a imposição está desligada. false desativa de forma fiável toda a imposição por país (ver recuperação abaixo). |
GEOIP_DB_PATH |
/app/data/geoip/GeoLite2-Country.mmdb |
Caminho para o ficheiro de base de dados .mmdb por país (preenchido automaticamente quando o GeoIP está ativo). |
GEOIP_AUTO_UPDATE |
true |
Descarregar a base automaticamente no arranque (DB-IP sem chave por predefinição; MaxMind quando MAXMIND_* estão definidos) quando está em falta ou mais antiga que GEOIP_AUTO_UPDATE_MAX_AGE_DAYS (25 por predefinição). Define false para gerir o ficheiro manualmente. |
SECURITY_GEOIP_ALLOWED_COUNTRIES |
(vazio) | Códigos de país ISO 3166-1 alpha-2 separados por vírgulas (p. ex. PL,DE,FR). Os códigos são normalizados para maiúsculas e validados; os inválidos são rejeitados. Vazio = sem restrição. Quando definido, este valor do operador prevalece sobre a definição do tenant na aplicação. |
Quando nenhuma lista de países está configurada, o filtro GeoIP é passivo — resolve códigos de país para fins de seguimento mas não bloqueia qualquer pedido. Ativar a filtragem por país na interface de administração usa um seletor de países validado (ISO 3166-1 alpha-2) e exige pelo menos um país e uma base de dados carregada.
Atualizar a base de dados: a descarga automática no arranque mantém-na razoavelmente atualizada, mas depois de substituir manualmente o ficheiro
.mmdbpode recarregá-lo sem reiniciar em Administração → Segurança → estado efetivo → Recarregar base de dados (um recarregamento protegido — um candidato corrompido ou em falta mantém a base de dados atualmente carregada). Um reinício do backend também adota o novo ficheiro. O painel de estado efetivo mostra se a base de dados está carregada, com as marcas temporais de compilação/carregamento.
Recuperação após um bloqueio de GeoIP
Se uma lista de países permitidos excluir acidentalmente o seu próprio país, recebe HTTP 403 com a sugestão de recuperação GEO_BLOCKED. Para recuperar o acesso:
- Defina
GEOIP_ENABLED=falseno ambiente do backend. - Reinicie o backend (isto desativa a aplicação de GeoIP antes de qualquer política ser avaliada).
- Corrija ou limpe a lista de países permitidos, depois defina
GEOIP_ENABLED=truee reinicie novamente.
Isto é independente do interruptor de recuperação da lista de permissões de IP — recuperar um nunca desativa o outro de forma silenciosa.
Considerações de privacidade
- A resolução GeoIP é sem estado — não é armazenada permanentemente qualquer correspondência IP-país.
- Para o seguimento de propostas é registado apenas o código do país (p. ex. «PT»), não o endereço IP em si.
- Os endereços IP registados nos eventos web das propostas estão sujeitos ao trabalho configurável de anonimização de IP, que os submete a hash após um número configurável de dias para conformidade com o RGPD.