Vai al contenuto
Q
QuoteNode

Wiki

GeoIP e controllo accessi geografico

Come QuoteNode usa un database GeoIP locale per il controllo accessi per Paese e il tracciamento delle offerte.

GeoIP e controllo accessi geografico

QuoteNode include un controllo accessi geografico opzionale e il tracciamento per Paese tramite un database GeoIP locale per Paese (DB-IP Country Lite senza chiave per impostazione predefinita, o MaxMind GeoLite2).

Due usi di GeoIP

1. Controllo accessi all’applicazione

Quando è attivo, il filtro GeoIP può limitare l’accesso all’applicazione a Paesi specifici. Le richieste da Paesi non consentiti ricevono HTTP 403 (Forbidden).

È utile alle organizzazioni che:

  • operano solo in determinate giurisdizioni,
  • vogliono ridurre l’esposizione ad attacchi automatizzati da certe regioni,
  • devono rispettare requisiti di residenza dei dati o di controllo accessi.

2. Tracciamento delle interazioni con l’offerta

Quando un cliente apre un link pubblico di un’offerta, il sistema registra il codice Paese del cliente (ISO 3166-1 alpha-2) insieme all’evento di interazione. Questo fornisce contesto geografico all’analisi delle offerte:

  • «La tua offerta è stata aperta dalla Germania» — conferma la portata internazionale,
  • «Più aperture da Paesi diversi» — può indicare che l’offerta è stata inoltrata.

Come funziona

Database

La risoluzione GeoIP usa un database locale per Paese in formato MaxMind DB (.mmdb) — non un’API esterna. Tutte le ricerche avvengono in memoria, senza chiamate di rete.

Per impostazione predefinita è l’edizione DB-IP Country Lite senza chiave (licenza CC-BY-4.0, nessun account necessario). Il container lo scarica automaticamente all’avvio (e con una pianificazione giornaliera) se manca o è obsoleto — indipendentemente da GEOIP_ENABLED, governato da GEOIP_AUTO_UPDATE (predefinito true). Il database può quindi essere pronto mentre l’applicazione per Paese è disattivata. Nessun download manuale né montaggio del file. Per usare invece MaxMind GeoLite2, imposta MAXMIND_ACCOUNT_ID / MAXMIND_LICENSE_KEY (un account MaxMind gratuito); è lo stesso formato .mmdb. Puoi anche popolare il file manualmente con scripts/update-geoip.sh.

Rilevamento dell’IP

L’IP del client è risolto interamente dall’applicazione — non viene preso ciecamente dalle intestazioni della richiesta. Un X-Forwarded-For, X-Real-IP o CF-Connecting-IP falsificato da un client diretto non può mai falsificare il controllo del Paese.

  1. L’applicazione prende il peer di trasporto (l’indirizzo che ha effettivamente aperto la connessione).
  2. Il peer è considerato attendibile solo quando è un proxy dichiarato esplicitamente — una voce in SECURITY_TRUSTED_PROXIES (IP/CIDR letterali separati da virgole e/o nomi di servizio Compose). Il servizio integrato frontend/caddy è dichiarato automaticamente, quindi gli stack standard di Docker/Coolify funzionano senza configurazione. Un indirizzo privato/loopback/CGNAT non è attendibile solo perché non è instradabile globalmente.
  3. Se il peer non è un proxy attendibile, tutte le intestazioni di inoltro vengono ignorate e il peer stesso è il client. Da un proxy attendibile, il client è l’unico e autorevole X-Real-IP; altrimenti la catena X-Forwarded-For percorsa da destra a sinistra saltando solo gli hop attendibili (il primo indirizzo non attendibile da destra è il client, anche se privato). Sono accettati solo IP letterali (nessun DNS). Il backend non legge mai CF-Connecting-IP — Cloudflare è gestito all’edge (sotto).

Dietro Cloudflare (automatico). Quando il deployment è dietro Cloudflare, il peer di trasporto rigoroso è un indirizzo edge di Cloudflare, non il visitatore. L’edge Caddy integrato (il Caddy del frontend in Coolify e il Caddy autonomo) lo normalizza automaticamente: una richiesta è trattata come Cloudflare solo quando l’IP che si connette rientra negli intervalli ufficiali pubblicati di Cloudflare e CF-Connecting-IP è un singolo IP ben formato; allora X-Real-IP è impostato su quel visitatore reale e CF-Connecting-IP è rimosso prima del backend. Un valore duplicato, in elenco o malformato fallisce in modo sicuro (fail-closed) verso l’indirizzo edge. Non aggiungi gli intervalli di Cloudflare a SECURITY_TRUSTED_PROXIES, e il backend continua a non fidarsi mai di un CF-Connecting-IP fornito dal client. L’elenco degli intervalli è versionato e aggiornato da scripts/sync-cloudflare-ips.sh, protetto da un controllo di deriva settimanale.

Dietro un altro CDN. Un CDN diverso da Cloudflare non è riconosciuto automaticamente. Normalizza l’IP del client al tuo edge nello stesso modo — imposta X-Real-IP sul visitatore reale ed elimina le intestazioni di inoltro non attendibili — prima che il traffico raggiunga il backend.

L’IP del client è un filtro approssimativo best-effort, non autenticazione. Chiunque possa raggiungere l’origine direttamente (aggirando CDN/proxy) potrebbe presentare un’intestazione di inoltro scelta; l’irrobustimento consigliato è limitare l’origine con un firewall così che solo il tuo CDN/proxy possa raggiungerla.

Gli indirizzi client non instradabili a livello globale (loopback, privati/RFC 1918, link-local, CGNAT, IPv6 ULA) non vengono mai geo-bloccati — non possono essere geolocalizzati — così gli health check da localhost e i deployment LAN/same-host continuano a funzionare mentre GeoIP è attivo. La whitelist IP e l’autenticazione continuano comunque ad applicarsi.

Percorsi esenti

I seguenti percorsi sono sempre esenti dalle restrizioni geografiche per restare raggiungibili in tutto il mondo:

  • link pubblici delle offerte (/offer/public/*) e branding pubblico (/api/v1/public/branding/*),
  • azioni dei link e-mail: disiscrizione (/api/v1/notifications/unsubscribe-token/*) e preferenze pubbliche (/api/v1/notifications/preferences-public/*),
  • endpoint di infrastruttura/salute (/health*, /actuator/health, /actuator/info).

L’autenticazione amministratore (/api/v1/auth/login, 2FA) e gli asset autenticati restano soggetti al controllo geografico.

Configurazione

Variabile Predefinito Descrizione
GEOIP_ENABLED false Solo interruttore dell’applicazione per Paese — anche interruttore di emergenza. Non influisce sul caricamento del database: il DB continua a caricarsi e aggiornarsi (vedi GEOIP_AUTO_UPDATE), quindi può essere pronto mentre l’applicazione è disattivata. false disattiva in modo affidabile tutta l’applicazione per Paese (vedi ripristino sotto).
GEOIP_DB_PATH /app/data/geoip/GeoLite2-Country.mmdb Percorso del file di database .mmdb per Paese (popolato automaticamente quando GeoIP è attivo).
GEOIP_AUTO_UPDATE true Scarica automaticamente il database all’avvio (DB-IP senza chiave per impostazione predefinita; MaxMind quando MAXMIND_* sono impostati) quando manca o è più vecchio di GEOIP_AUTO_UPDATE_MAX_AGE_DAYS (valore predefinito dell’applicazione 35; il modello di produzione imposta esplicitamente 25). Imposta false per gestire il file da solo.
GEOIP_AUTO_UPDATE_MAX_AGE_DAYS 35 Età oltre la quale il database è considerato obsoleto e viene riscaricato. È il valore di ripiego dell’applicazione; infra/.env.prod.example lo sovrascrive con un 25 esplicito, quindi un deployment che omette la chiave ottiene 35.
GEOIP_UPDATE_SCHEDULER_ENABLED true Interruttore del controllo periodico di obsolescenza. Arriva attivo perché un database dei paesi obsoleto è lo stato non sicuro. Disattivarlo non tocca l’aggiornamento all’avvio né gli aggiornamenti manuali.
GEOIP_UPDATE_CRON 0 15 3 * * * Quando viene eseguito il controllo periodico, nel fuso orario del server (UTC se non imposti TZ). Una pianificazione giornaliera è un controllo giornaliero, non un download giornaliero: il file viene scaricato solo se manca o è obsoleto. Il modello supportato è un aggiornatore per percorso del database.
SECURITY_GEOIP_ALLOWED_COUNTRIES (vuoto) Codici Paese ISO 3166-1 alpha-2 separati da virgole (es. PL,DE,FR). I codici sono normalizzati in maiuscolo e validati; quelli non validi sono rifiutati. Vuoto = nessuna restrizione. Quando impostato, questo valore dell’operatore prevale sull’impostazione del tenant nell’applicazione.

Quando non è configurata alcuna lista di Paesi, il filtro GeoIP è passivo — risolve i codici Paese a scopo di tracciamento ma non blocca alcuna richiesta. Attivare il filtro per Paese nell’interfaccia di amministrazione usa un selettore di Paesi validato (ISO 3166-1 alpha-2) e richiede almeno un Paese e un database caricato.

Aggiornare il database: il download automatico all’avvio lo mantiene ragionevolmente aggiornato, ma dopo aver sostituito manualmente il file .mmdb puoi ricaricarlo senza riavvio da Amministrazione → Sicurezza → stato effettivo → Ricarica database (una ricarica protetta — un candidato corrotto o mancante mantiene il database attualmente caricato). Anche un riavvio del backend acquisisce il nuovo file. Il pannello dello stato effettivo mostra se il database è caricato, con le marche temporali di build/caricamento.

Ripristino dopo un blocco GeoIP

Se una lista di Paesi consentiti esclude accidentalmente il tuo Paese, ricevi HTTP 403 con il suggerimento di ripristino GEO_BLOCKED. Per ripristinare l’accesso:

  1. Imposta GEOIP_ENABLED=false nell’ambiente del backend.
  2. Riavvia il backend (questo disattiva l’applicazione di GeoIP prima che venga valutata qualsiasi politica).
  3. Correggi o svuota la lista dei Paesi consentiti, poi imposta GEOIP_ENABLED=true e riavvia di nuovo.

È indipendente dall’interruttore di ripristino della whitelist IP — ripristinare uno non disattiva mai silenziosamente l’altro.

Considerazioni sulla privacy

  • La risoluzione GeoIP è stateless — nessuna corrispondenza IP-Paese viene memorizzata in modo permanente.
  • Per il tracciamento delle offerte viene registrato solo il codice Paese (es. «IT»), non l’indirizzo IP stesso.
  • Gli indirizzi IP registrati negli eventi web delle offerte sono soggetti al job configurabile di anonimizzazione IP, che li sottopone a hash dopo un numero configurabile di giorni per la conformità al GDPR.

Last reviewed: Recently