Ir para o conteúdo
Q
QuoteNode

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.

  1. A aplicação toma o par de transporte (o endereço que efetivamente abriu a ligação).
  2. O par só é considerado de confiança quando é um proxy declarado explicitamente — uma entrada em SECURITY_TRUSTED_PROXIES (IP/CIDR literais separados por vírgulas e/ou nomes de serviço do Compose). O serviço integrado frontend/caddy é declarado automaticamente, pelo que os stacks padrão de Docker/Coolify funcionam sem configuração. Um endereço privado/loopback/CGNAT não é de confiança apenas por não ser roteável globalmente.
  3. Se o par não for um proxy de confiança, todos os cabeçalhos de reencaminhamento são ignorados e o próprio par é o cliente. A partir de um proxy de confiança, o cliente é o único e autoritativo X-Real-IP; caso contrário, a cadeia X-Forwarded-For percorrida da direita para a esquerda, ignorando apenas os saltos de confiança (o primeiro endereço não fiável a partir da direita é o cliente, mesmo que seja privado). Apenas são aceites IP literais (sem DNS). O backend nunca lê CF-Connecting-IP — a Cloudflare é tratada na edge (abaixo).

Atrás da Cloudflare (automático). Quando a implantação está atrás da Cloudflare, o par de transporte estrito é um endereço de edge da Cloudflare, não o visitante. A edge Caddy integrada (o Caddy do frontend no Coolify e o Caddy autónomo) normaliza isto automaticamente: um pedido só é tratado como Cloudflare quando o IP que se liga está dentro das gamas oficiais publicadas da Cloudflare e o CF-Connecting-IP é um único IP bem formado; então X-Real-IP é definido para esse visitante real e o CF-Connecting-IP é removido antes do backend. Um valor duplicado, em lista ou malformado falha de forma segura (fail-closed) para o endereço de edge. Não adiciona as gamas da Cloudflare a SECURITY_TRUSTED_PROXIES, e o backend continua a nunca confiar num CF-Connecting-IP fornecido pelo cliente. A lista de gamas é versionada e atualizada por scripts/sync-cloudflare-ips.sh, protegida por uma verificação de desvio semanal.

Atrás de outro CDN. Um CDN que não seja a Cloudflare não é reconhecido automaticamente. Normalize o IP do cliente na sua própria edge da mesma forma — defina X-Real-IP para o visitante real e descarte os cabeçalhos de reencaminhamento não fiáveis — antes de o tráfego chegar ao backend.

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 cabeçalho de reencaminhamento à 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 (predefinição da aplicação 35; o modelo de produção define explicitamente 25). Define false para gerir o ficheiro manualmente.
GEOIP_AUTO_UPDATE_MAX_AGE_DAYS 35 Idade a partir da qual a base é considerada desatualizada e volta a ser descarregada. É a predefinição da aplicação; infra/.env.prod.example substitui-a por um 25 explícito, por isso uma instalação que omita a chave obtém 35.
GEOIP_UPDATE_SCHEDULER_ENABLED true Interruptor da verificação periódica de desatualização. Vem ligado porque uma base de países desatualizada é o estado inseguro. Desligá-lo não afeta a atualização no arranque nem as atualizações manuais.
GEOIP_UPDATE_CRON 0 15 3 * * * Quando a verificação periódica corre, no fuso horário do servidor (UTC salvo se definir TZ). Um agendamento diário é uma verificação diária, não um download diário: o ficheiro só é obtido se faltar ou estiver desatualizado. O modelo suportado é um atualizador por caminho da base.
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 .mmdb pode 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:

  1. Defina GEOIP_ENABLED=false no ambiente do backend.
  2. Reinicie o backend (isto desativa a aplicação de GeoIP antes de qualquer política ser avaliada).
  3. Corrija ou limpe a lista de países permitidos, depois defina GEOIP_ENABLED=true e 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.

Last reviewed: Recently