Indice

Discussione di Tutanum

Rete

Rete

IPv6 e MAC Address

Dalla versione 6 di IP, nonché IPv6, se non in privacy mode e temporary address, il programma che lo gestisce genera due indirizzi che sono un insieme di caratteri più quelli del MAC Address della NIC (Network Interface Controller, la scheda di rete): gli indirizzi sono uno IPv6 pubblico e uno IPv6 locale, ma di solito viene usato solo uno dei due.
IPv6 è un'altra tecnologia rispetto ad IPv4 e non è una banale aggiunta di bytes; tale protocollo di rete si accende da solo con la tecnologia SLAAC appena gli arriva advertisment dal router o da apparati di rete simili, e accendendosi autonomamente genera i due indirizzi, non avendo pertanto più bisogno di NAT.
Il metodo che ha IPv6 per assegnare gli indirizzi su una rete locale è quello di incapsulare i 48 bit dell'indirizzo MAC nell'indirizzo IPv6 e questo si chiama EUI. Circa 10 anni fa gli utenti hanno iniziato a rendersi conto che si trattava di un problema di privacy. Poco dopo le funzionalità di configurazione per disabilitarlo a livello del sistema operativo sono state pubblicate per Windows, MacOS, GNU Linux e gli ambienti BSD. Il problema di IPv6 è che in caso di disabilitazione dell'interfaccia inet6, riappare da sola come se niente fosse stato modificato. Riappare perché si configura da sola con lo SLAAC non appena riceve un messaggio advertisment in broadcast dal router o da apparati simili. E guardacaso i DDoS hanno successo soprattutto se rimane attivo IPv6. Pertanto al fine di risolvere questo problema di privacy risulta inevitabile disabilitare completamente l'interfaccia inet6.
Nel caso di GNU Linux è possibile disabilitare da Grub o da kernel IPv6: da kernel basta digitare sudo sysctl net.ipv6.conf.all.disable_ipv6=1, mentre per il Grub basta modificare il file /etc/default/grub aggiungendo alla fine della riga ipv6.disable=1, (es.: GRUB\_CMDLINE\_LINUX\_DEFAULT="rd.lvm.lv=rhel/swap crashkernel=auto rd.lvm.lv=rhel/root ipv6.disable=1"), per poi rigenerare il file grub.cfg con il comando sudo grub-mkconfig -o /boot/grub2/grub.cfg o sudo update-grub.
Per IPv4 il MAC Address è valido solo all'interno della LAN e quando si passa attraverso il router, cambia l'indirizzo MAC con il suo. In remoto non c'è modo di vedere l'indirizzo MAC di un host. Ma comunque se l'host ha una connessione diretta con un server, è possibile chiedere al browser molte informazioni, soprattutto se è presente codice JavaScript malevolo.
Per IPv6 è un po' diverso e la visibilità di indirizzi MAC dagli indirizzi rimane persistente. Sono stati sviluppati un paio di RFC per risolvere questo problema:

La maggior parte dei dispositivi è esposta a questa problema, ma sugli apparati Wi-Fi è un po' diverso, in quanto non ci sono ancora vulnerabilità definite ma solo ricerche in auge.
IPv6 viene considerato attualmente infatti un problema di privacy dal momento che non viene abilitata la privacy extension, modalità disabilitata tra l'altro solitamente di default dalla stragrande maggioranza dei sistemi operativi.
È possibile addirittura verificare dal proprio smartphone se IPv6 sia abilitato di default:

  1. Scollegarsi dal Wi-Fi e dalla connessione dati, da ogni rete, mettendo così offline il sistema operativo.
  2. Usare un terminale come Termux e digitare ip a, ip link e ifconfig, prendendo il MAC Address, segnandolo da qualche parte.
  3. Collegarsi alla WLAN Wi-Fi riabilitandolo, ripetendo i comandi per rileggere il valore dell'IPv6.

Per le interfacce rmnet_data0 e wlan0, privacy mode non è attivato, e il MAC e l'IPv6 combaciano similarmente:
Esempio:
MAC = 62:52:95:01:d7:87
IPV6 = fe80::6052:95ff:fe01:d7:87

Si tratta di EUI-64, quindi di un problema di privacy persistente, poiché i valori 6-52-95-d7-87 risultano presenti. Per potere verificare se la privacy mode è attiva basta digitare:

sysctl net.ipv6.conf.all.use_tempaddr

Nel caso siano pari a 1 o a 2 sono abilitate, mentre se viene restituito 0 sono disabilitate.
Cosa tuttavia che suscita qualche dubbio dal momento in base al seguente comando preso in questa guida:

ip -o addr show dev ens4v1 | grep temporary | wc -l 2

Nella maggior parte dei casi restituisce il valore 0.
Sulla wiki di Arch Linux e di Gentoo sono presenti dei passi su come abilitare le privacy extension.
Immaginatevi qualche miliardo di dispositivi, soprattutto IPv6, di cui si conoscono dati di geolocalizzazione perché si vanno ad incrociare dati tra BSSID, MAC Address di Access Point tenuti in memoria e IPv6 EUI-64 del dispositivo collegato ad una WAN, come ad esempio uno smartphone. E pensate magari che esiste anche la pratica di utilizzare le automobili di StreetView, il servizio di Google Maps per intenderci, per potere scannerizzare le reti Wi-Fi al fine di attuare una ricerca sui dati relativi ai dispositivi collegati, più altre molte informazioni, come i nomi, i BSSID e gli ESSID.
Poi tenendo da conto che il servizio di geolocalizzazione usa l'incrocio tra Wi-Fi, Bluetooth e GPS, capiamo che la privacy viene annichilita. Esistono articoli e database solo di geolocalizzazione delle reti Wi-Fi, per dirla tutta.
Con i server, in generale, è relativamente più facile rispetto ai client, perché usando solo l'ethernet, basta disabilitare tutti gli applicativi come NetworkManager, neplan, iw, etc., usando di conseguenza solo conf ifup e ifdown.
Per ulteriori approfondimenti, qui e qui viene argomentato come avviene il tracciamento con IPv6 SLAAC più EUI-64, mentre qui viene messo a disposizione uno strumento per potere ricavare un Mac Address partendo dall'IPv6.
Le soluzioni rispetto a questa problematica sono, in sintesi, le seguenti:

  1. Generare gli IPv6 con privacy mode attivata, anche se per un server non andrebbe bene poiché cambierebbe ogni giorno.
  2. Disabilitare inet6, l'interfaccia di rete che si occupa della generazione e della gestione degli IPv6 (sia da boot loader sia da kernel, con conseguente reboot): alcuni programmi potrebbero avere problemi a riconfigurarsi senza IPv6, come per esempio avviene con NTP.
  3. Bloccare tutte le richieste IPv6 a livello di firewall.
  4. Generare un MAC Address nuovo ma renderlo persistente, una via di mezzo, così se se si dovesse generare IPv6 in SLAAC EUI-64, almeno non andrebbe ad identificare il NIC in modo univoco, seppur identificherebbe tuttavia il router di provenienza.

IPv6 come via di raggiungibilità dietro CGNAT

Finora l'IPv6 è stato trattato come rischio di privacy (SLAAC ed EUI-64 che incapsulano il MAC). Esiste però un uso opposto e controllato: quando il nodo è dietro CGNAT e non può ricevere connessioni in entrata, un indirizzo IPv6 globale può renderlo direttamente raggiungibile senza perdere l'anonimato.

Il problema: con la CGNAT, e in particolare con il NAT simmetrico, il nodo non possiede un IPv4 pubblico né una porta esterna stabile (l'indirizzo è condiviso fra molti clienti). Un servizio nascosto, come un eepsite I2P o un onion service, fatica o non riesce a pubblicarsi perché i peer non riescono a stabilire connessioni in ingresso. Le linee moderne, spesso in DS-Lite, offrono però un IPv6 nativo e instradabile anche quando l'IPv4 è sotto CGNAT: aprendo un singolo pinhole sul firewall per la sola porta dei trasporti si ottiene un recapito diretto, senza traduzione di porta.

Perché ciò non indebolisce l'anonimato va spiegato con cura. I peer della rete di overlay vedono comunque l'indirizzo di trasporto del nodo, sia esso IPv4 o IPv6: l'anonimato non nasce dal nascondere quell'indirizzo, ma dalla stratificazione dei tunnel (vedi l'architettura di I2P). Usare IPv6 al posto di IPv4 non cambia questo, a patto di rispettare tre regole:

  • Niente SLAAC. Disabilitare accept_rtadv sull'interfaccia e assegnare un indirizzo statico con suffisso casuale/opaco (nello spirito della RFC-7217), così il MAC non finisce mai nell'indirizzo e non si riformano gli indirizzi EUI-64.
  • Rotta di default statica verso il link-local del gateway, per non dipendere dagli advertisement del router (che rigenererebbero gli indirizzi SLAAC).
  • Uscita ristretta al solo demone del servizio. Nel firewall si consente l'uscita IPv6 soltanto all'utente/uid del processo che offre il servizio: nessun altro programma del sistema deve poter uscire in IPv6, per non creare canali di correlazione.

Una trappola da conoscere, perché fa perdere ore: se l'IPv6 sembra morto (nessun pacchetto esce, l'applicazione riceve errori di permesso) pur essendo configurato correttamente, sospettare un filtro di pacchetti a livello 2. Alcuni firewall filtrano anche gli ethertype: se la regola che lascia passare l'IPv4 (0x0800) e l'ARP (0x0806) non ha la gemella per l'IPv6 (0x86dd), tutti i frame IPv6 vengono scartati in silenzio prima ancora di lasciare la scheda, e nemmeno le Neighbor Solicitation escono. Allo stesso modo, su un hypervisor o un bridge il multicast IPv6, indispensabile all'NDP, può essere soppresso (snooping senza querier). Conviene verificare questi strati prima di dare la colpa allo stack di rete.

Proxy

La sicurezza delle reti moderne si basa su due pilastri fondamentali: il controllo del traffico e la protezione della risoluzione DNS.
Il controllo del traffico viene attuato solitamente tramite firewall o tramite proxy, i quali fungono da intermediari tra client e server, permettendo di filtrare, autenticare e monitorare le comunicazioni. La protezione della risoluzione dei DNS avviene solitamente tramite proxy ed è tradizionalmente permessa in chiaro, cosa che la rende vulnerabile ad intercettazioni ed a manipolazioni. Su Tor i DNS sono visibili unicamente all'ultimo nodo, all'entry node del circuito onion se viene contattato un hidden service, all'exit node nel caso sia invece contattato un host del clear web. DNSCrypt ad ogni modo nasce per cifrare ed autenticare le query eseguite per il clear web.
Il proxy è un nodo che riceve le richieste dal client e le inoltra sul server di destinazione. Può essere di tre tipi: forward proxy (interposto tra client e internet), reverse proxy (davanti ad un server, per bilanciare carico e protezione) e SOCKS/HTTP proxy, usato per tunneling o filtraggio. Generalmente Tor utilizza SOCKS5 come proxy ed è generico, opera al livello 5 del modello ISO/OSI e utilizza il metodo del tunneling. Come riporta la documentazione di Tor, le applicazioni che usano SOCKS5 saranno consapevoli del tunneling, ma è possibile evitare la correlazione dell'identità solo se configurato correttamente.
La logica di hardening relativa alla configurazione del proxy consiste nel ridurre al minimo i vettori di attacco controllando rigorosamente ciò che passa dal proxy, cosa che potrebbe benissimo essere integrata ad un qualsiasi SIEM per l'apertura di segnalazioni critiche analizzabili in un secondo momento dall'operatore.
Le componenti essenziali di un proxy ben configurato riguardano:

  • Un'autenticazione forte, così che nessuno dovrebbe potere usare il proxy senza identificarsi, se si parla di un proxy privato.
  • La limitazione delle porte e dei protocolli, permettendo solo ciò che serve, bloccando invece tutto il resto.
  • Aggiornamenti frequenti, così che si possa mitigare al problema della complessità, da cui deriva anche il problema delle vulnerabilità.
  • La segregazione, così che esso sia posizionato in una zona controllata della rete, impedendo accessi a dati sensibili e potenzialmente esfiltrabili.
Ogni volta che si naviga su un sito web, il dispositivo deve risolvere il DNS e chiunque intercetti il traffico DNS può sapere quali siti l'utente visita. Un aggressore potrebbe potenzialmente inoltre manipolare le risposte DNS, facendo attacchi di DNS spoofing. DNSCrypt è un protocollo per cifrare e autenticare le query DNS, ed è utilizzato pertanto per mitigare queste problematiche.
Parallelamente a DNSCrypt, esistono altri protocolli come:
  • DNS over TLS (DoT): le query DNS passano dentro una connessione TLS come HTTPS.
  • DNS over HTTPS (DoH): le query DNS viaggiano in una connessione HTTPS vera e propria, mimetizzandosi tra il normale traffico web.
  • Oblivious DoH (ODoH): aggiunge un ulteriore strato di anonimato, separando l'identità del client dal contenuto della query.
Tenendo da conto DNSCrypt, il software più diffuso per poterlo gestire è dnscrypt-proxy, configurabile tramite il file dnscrypt-proxy.toml, nella quale può essere dichiarato il resolver (come Quad9, NextDNS che teoricamente non producono log), il metodo DoH o DoT, le opzioni di anonymized DNS che instradano le richieste e l'integrazione delle liste di blocco per pubblicità, tracker e malware. Per configurare al meglio dnscrypt-proxy è necessario:
  • Usare più resolver, facendo ruotare la query, così da non concentrare i log su un unico fornitore.
  • Attivare Anonymized DNS relays, in modo che il resolver finale non veda l'IP.
  • Abbinare DNSCrypt ad un proxy ulteriore o ad una VPN, ottenendo più strati di offuscamento.
  • Monitorare i leak così che anche solo una singola richiesta DNS non cifrata possa rivelare troppe informazioni.
Per configurare dnscrypt-proxy con Tor è possibile pertanto configurarlo come segue (modificando la porta in base alla propria configurazione):
listen_addresses = ['127.0.0.1:53'] max_clients = 250 keepalive = 30 proxy = "socks5://127.0.0.1:9050" force_tcp = true ignore_system_dns = true dnscrypt_servers = true doh_servers = true require_dnssec = true require_nolog = true require_nofilter = true [anonymized_dns] routes = [ { server_name='*', via=['anon-cs-fr', 'anon-cs-nl', 'anon-cs-de'] } ] skip_incompatible = true lb_strategy = 'p2' netprobe_timeout = 60 log_files_max_size = 0 log_level = 0 use_syslog = false fallback_resolvers = [] [blocked_names] blocked_names_file = '/etc/dnscrypt-proxy/blacklist.txt' [blocked_ips] blocked_ips_file = '/etc/dnscrypt-proxy/ips-blacklist.txt' tls_disable_session_tickets = true tls_cipher_suite = [52392, 49195, 49199, 49200] block_ipv6 = true block_undelegated = true block_fragments = true
I file blacklist.txt e ips-blacklist.txt sono file di blocco, rispettivamente per i DNS e per gli IP.

Un elemento relativo al proxy, in questo caso DNS, è l'header della chiamata che viene instradata, ed in particolar modo l'elemento contrassegnato come X-Forwarded-For (abbreviato a XFF). È un'intestazione HTTP con standard che permette di identificare l'indirizzo IP originale del client quando la richiesta passa attraverso uno o più proxy o load balancer. Quando un client si connette direttamente ad un server, quest'ultimo vede l'IP del client. Se invece la connessione passa tramite un proxy, il server vede solo l'IP del proxy.
Per non perdere l'informazione sull'IP originale, il proxy inserisce l'header X-Forwarded-For nella richiesta.
Il primo indirizzo IP è sempre il client originale, mentre gli indirizzi successivi sono i proxy attraversati in ordine, per esempio X-Forwarded-For: client-IP, proxy1-IP, proxy2-IP, ...
L'header X-Forwarded-For viene comunemente utilizzato per logging, analisi e sicurezza, permettendo ai server di registrare l'IP reale del client anche quando la richiesta passa attraverso più livelli di proxy. Tuttavia, l'uso di XFF comporta anche rischi per l'anonimato e la privacy. Se non gestito correttamente, può rivelare l'IP originale di utenti che utilizzano VPN o Tor, esponendo informazioni sensibili e rendendo possibile il tracciamento o la profilazione dell'utente. Un altro rischio è la falsificazione dell'header: un client malintenzionato può inserire un valore XFF fasullo per fingersi un altro IP, bypassare controlli basati sull'IP o inquinare i log del server. Inoltre, valori malevoli inseriti nell'XFF possono provocare problemi di sicurezza, come l'iniezione di comandi nei sistemi di log o negli strumenti di analisi automatizzata. Per mitigare questi rischi è consigliabile adottare le seguenti best practice:
  • Accettare e registrare XFF solo da proxy affidabili, ignorando eventuali header inviati direttamente dai client.
  • Considerare l'uso dell'header standard Forwarded (RFC 7239) che offre una struttura più sicura e dettagliata rispetto a XFF.
  • Non affidarsi unicamente all'XFF per applicare regole di sicurezza o autenticazione; combinare con altri metodi, come controlli basati su sessioni o token.
  • Filtrare o rimuovere l'XFF in uscita dai log pubblici o dalle API per evitare la divulgazione involontaria dell'IP reale degli utenti.
L'header è un aspetto tuttavia più legato al servizio offerto come può esserlo un web server anziché a servizi come DNSCrypt, pertanto al fine di completare il discorso relativo ai proxy, proponiamo qui di seguito la configurazione di dnscrypt-proxy:
# Ascolto locale solo su IPv4 listen_addresses = ['127.0.0.1:5354'] max_clients = 250 keepalive = 30 ignore_system_dns = true # Forza uso DNSCrypt, DoH e relay anonimi dnscrypt_servers = true doh_servers = false odoh_servers = false # Solo resolver affidabili ipv4_servers = true ipv6_servers = false require_dnssec = true require_nolog = true require_nofilter = true # Blocchi per privacy block_ipv6 = true block_unqualified = true block_undelegated = true reject_ttl = 600 # Cache sicura cache = true cache_size = 4096 cache_min_ttl = 2400 cache_max_ttl = 86400 cache_neg_ttl = 60 cache_neg_max_ttl = 600 # Timeout e rete timeout = 5000 netprobe_timeout = -1 netprobe_address = '9.9.9.9:53' force_tcp = true # TCP riduce frammentazione e MITM # Tor SOCKS5 per instradare tutte le query proxy = 'socks5://127.0.0.1:9050' # Niente relay anonimi insieme a Tor. Provato su FreeBSD 15.1: con il proxy di Tor e i relay attivi ogni # richiesta va in timeout. Attraverso Tor il resolver vede già soltanto l'uscita di Tor: i relay non # aggiungono nulla. Senza Tor, invece, sono loro a nascondere l'indirizzo (vedi config/dnscrypt-proxy.toml). [anonymized_dns] routes = [] # Blocchi di domini e IP per anti-tracking e malware [blocked_names] blocked_names_file = '/etc/dnscrypt-proxy/blacklist.txt' [blocked_ips] blocked_ips_file = '/etc/dnscrypt-proxy/ip-blacklist.txt' [allowed_names] allowed_names_file = '/etc/dnscrypt-proxy/whitelist.txt' # Log minimali (privacy massima) log_level = 0 log_file = '' use_syslog = false log_files_max_size = 0 # Resolver predefiniti di bootstrap cifrati bootstrap_resolvers = ['9.9.9.9:53', '9.9.9.10:53'] cert_refresh_delay = 240 dnscrypt_ephemeral_keys = true tls_disable_session_tickets = true # Forwarding e cloaking (opzionale) forwarding_rules = '/etc/dnscrypt-proxy/forwarding-rules.txt' cloaking_rules = '/etc/dnscrypt-proxy/cloaking-rules.txt' # Query log per debug interno (facoltativo) [query_log] format = 'tsv' file = '/etc/dnscrypt-proxy/cache/query.log' ignored_qtypes = ['DNSKEY', 'NS'] [nx_log] format = 'tsv' file = '/etc/dnscrypt-proxy/cache/nx.log'

Pi-hole

DNSCrypt protegge le richieste DNS lungo il percorso, ma non decide quali richieste meritino una risposta. Pi-hole fa esattamente questo: è un server DNS per la rete locale che rifiuta di risolvere i domini di pubblicità, tracciamento e telemetria, per tutti i dispositivi che lo usano e senza installare nulla su di essi. Riguarda la rete di casa, non il nodo: un server non naviga, ma televisori, telefoni ed elettrodomestici connessi parlano di continuo con chi li ha prodotti.

Come funziona

Il meccanismo si chiama DNS sinkhole. Ogni dispositivo chiede a Pi-hole l'indirizzo di un nome; se il nome è in una lista di blocco la risposta è un indirizzo nullo, e la connessione non parte nemmeno. Altrimenti la richiesta prosegue verso il server a monte.

Dispositivi di casatelefoni, TV, portatiliPi-holefiltra e registradnscrypt-proxy sul nodocifra, relay anonimiResolversenza registriDominio in lista:risposta nullaRouter: ogni richiesta DNS diretta altroveviene dirottata verso Pi-hole o scartata
Pi-hole decide che cosa non risolvere, dnscrypt-proxy protegge ciò che viene risolto. Il router impedisce ai dispositivi di scavalcare entrambi.

I componenti sono pochi.

  • FTL: il demone pihole-FTL, derivato da dnsmasq. Risponde alle richieste, tiene la cache e le statistiche. Dalla versione 6 contiene anche il server web e l'API, e la configurazione sta in un solo file, /etc/pihole/pihole.toml.
  • Gravity: le liste di blocco, scaricate e compilate in un database SQLite (gravity.db), più le regole proprie: domini esatti, espressioni regolari, eccezioni.
  • Registro delle richieste: un secondo database (pihole-FTL.db) con ogni nome chiesto da ogni dispositivo.
  • Gruppi: liste diverse per dispositivi diversi, così che il televisore sia trattato più severamente del portatile.
  • Interfaccia web e riga di comando (pihole).

Che cosa offre a Tutanum

  • Protegge ciò che non si può configurare: su un televisore o su un telefono non si installa un filtro. Con Pi-hole basta che il dispositivo usi il DNS della rete.
  • Riduce la telemetria alla fonte: la richiesta bloccata non lascia la casa, quindi non rivela nemmeno che il dispositivo esiste.
  • Rende visibile la rete: il registro mostra quale dispositivo cerca che cosa. Un elettrodomestico che interroga centinaia di nomi mai visti, o nomi casuali che non esistono, è un segnale di compromissione. È una sorgente in più per la correlazione descritta in Da EDR a XDR.
  • Usa gli indicatori già raccolti: i domini malevoli dei feed MISP diventano una lista di blocco locale (vedi MISP e SIEM).
  • Si compone con DNSCrypt: Pi-hole filtra, dnscrypt-proxy cifra e anonimizza. Nessuno dei due fa il lavoro dell'altro.

I limiti

  • Vede solo i nomi: non blocca la pubblicità servita dallo stesso dominio del contenuto, né le connessioni dirette a un indirizzo IP scritto nel programma.
  • Si scavalca con il DNS cifrato: un browser con DNS-over-HTTPS, un telefono con il DNS privato o un dispositivo con 8.8.8.8 cablato dentro ignorano il DNS della rete. Pi-hole risponde al dominio di controllo con cui Firefox decide se usare DoH, ma per il resto serve il firewall: dirottare la porta 53, chiudere la 853, bloccare i server DoH noti. È una rincorsa, non una soluzione definitiva.
  • Non dà anonimato: il server a monte vede comunque le richieste. Per questo a monte ci va dnscrypt-proxy, mai il resolver del provider.
  • Il registro è un diario: elenca ciò che ogni persona di casa visita, con l'ora. È il dato più sensibile che Pi-hole produce, e chi sequestra o viola la macchina lo trova pronto.
  • È un punto unico di guasto: se cade, in casa non si risolve più nulla, e la tentazione di rimettere il DNS del provider è forte.
  • Non riguarda Tor: ciò che passa da Tor viene risolto all'uscita del circuito e non attraversa Pi-hole, com'è giusto che sia.
  • Liste di terzi: ciò che viene bloccato lo decide chi mantiene le liste. Vanno scelte, scaricate attraverso Tor e riviste.

Pi-hole e i valori del progetto

ValorePi-holeGiudizio
Software liberoLicenza EUPL, codice pubblico, progetto di volontari finanziato da donazioniRispettato
Decentralizzazione e auto-ospitabilitàGira in casa, non dipende da un servizio esternoRispettato
PrivacyNessuna telemetria; contatta l'esterno per le liste e per il controllo delle versioni. Il registro delle richieste va però domatoRispettato, con riserva
Accessibilità e riusoNato per un Raspberry Pi, gira su qualunque computer di recuperoRispettato
Semplicità (KISS)Un demone, due database e un'interfaccia web, dove una lista di blocco in dnscrypt-proxy è un file di testoRispettato in parte
Sistemi BSDSupporta ufficialmente solo distribuzioni GNU/Linux, e si appoggia a systemd. Su FreeBSD e OpenBSD non è previstoNon rispettato
Installazione verificabileIl metodo consigliato è scaricare uno script e passarlo direttamente a una shell di rootNon rispettato, ma evitabile

Le alternative minime

Liste in dnscrypt-proxyUnboundPi-hole
Che cos'èUn file di nomi da bloccare, nel proxy che il nodo ha già Il resolver di base di FreeBSD e OpenBSD, con zone locali di blocco Un servizio dedicato con interfaccia
SistemiTuttiTuttiSolo GNU/Linux
Regole per dispositivoNoLimitateSì, a gruppi
Visibilità per dispositivoUn file di logUn file di log Statistiche, ricerca, grafici
Codice in piùNessunoNessunoDemone, database, web

Quando usarlo

Per il nodo in sé non serve: basta la lista di blocco di dnscrypt-proxy, descritta in Tutanum Classico. È la scelta coerente con il KISS, e gira su FreeBSD.

Pi-hole diventa utile quando il nodo deve proteggere la rete di casa e si vuole sapere che cosa fanno i dispositivi che la abitano. Poiché richiede GNU/Linux, il suo posto naturale è un Tutanum Lieve: un computer di recupero dedicato, oppure una macchina virtuale sotto Proxmox. Su un Classico starebbe in una macchina virtuale bhyve, mai sull'host. In ogni caso a monte c'è il dnscrypt-proxy del nodo, e accanto c'è il firewall che impedisce di scavalcarlo.

Tre regole lo riportano dentro i valori del progetto: si installa dal repository verificato e non con lo script passato alla shell, l'interfaccia web ascolta solo in locale, e il registro delle richieste si tiene per pochi giorni o non si tiene affatto. Quest'ultima è una scelta vera, perché visibilità e riservatezza qui si escludono: chi vuole usare Pi-hole come sensore conserva il dettaglio per poco tempo, chi vuole solo il filtro lo spegne. I comandi sono in Tutanum Lieve.

Firewall

Il principio è uno solo: default-deny, cioè bloccare tutto e aprire solo i servizi strettamente necessari. Un firewall filtra per protocollo, porta e indirizzo e, con i moduli giusti, anche in base a contenuto e metadati.

pf (FreeBSD e OpenBSD)

Su un nodo Tutanum si usa pf, ottimo al livello 3 (rete). Configurazione minimale default-deny che lascia uscire il traffico con stato e apre solo le porte dei servizi (qui SSH e, come commento, le porte di I2P o del servizio onion):

# /etc/pf.conf: esempio minimo. Sul nodo Tutanum anche l'uscita è ristretta e le interfacce di # loopback non si saltano, perché ci passa il traffico tra le jail: vedi "Configurazioni di esempio" e config/pf.conf set skip on lo0 set block-policy drop block all pass out quick keep state pass in quick proto tcp to port { 22 } keep state # aggiungere qui le porte dei servizi esposti (tunnel I2P, onion, ecc.) doas pfctl -f /etc/pf.conf # carica le regole doas pfctl -e # abilita pf

pf copre bene il livello 3 ma non il livello 2 (frame, ARP): per quello servono strumenti dedicati a parte.

Filtro di livello 2 e ordine di avvio

Siccome pf non vede i frame, per il livello 2 su FreeBSD si usa ipfw con il filtro ethernet attivo (net.link.ether.ipfw=1). Il ruleset tiene un default-deny di livello 2 che lascia passare solo gli ethertype legittimi (ARP, IPv4, IPv6) e scarta il resto, e vi si affiancano regole anti fingerprint che scartano le firme TCP tipiche delle scansioni. Vanno distinti due interruttori: net.inet.ip.fw.enable è il master (se vale 0 ipfw non filtra nulla, nemmeno a livello 2), mentre net.link.ether.ipfw abilita solo l'esame dei frame. Caricare il file delle regole non accende il master da solo.

La trappola, pagata cara in fase di costruzione, è l'ordine di accensione quando sul nodo girano delle jail. Avviare una jail mentre il filtro di livello 2 è già acceso può tranciare di netto la rete locale: il nodo smette di rispondere perfino all'ARP e appare irraggiungibile ("no route to host"), pur avendo un carico bassissimo. È il sintomo chiave che smaschera il problema: non è saturazione di CPU o di RAM, è il filtro dei frame che collide con la messa in rete della jail. Il filtro di livello 2 acceso e le jail già avviate, invece, convivono senza problemi.

La soluzione è non caricare ipfw durante il boot, far partire prima tutte le jail e accendere il filtro di livello 2 per ultimo, con un hook ritardato che aspetta che i servizi siano su e poi carica il ruleset. Conviene che quell'hook faccia un controllo di integrità: dopo l'accensione verifica che le regole di allow critiche (ARP e IPv4) siano davvero presenti e, se il ruleset si è caricato a metà lasciando un deny totale, rispegne subito ipfw da solo, così un errore non si traduce mai in un blocco fuori. Allo spegnimento vale il contrario: disattivare il filtro di livello 2 prima di fermare le jail.

Congelare il firewall nel kernel: securelevel, con prudenza

FreeBSD permette di alzare il securelevel a 2, che congela le regole del firewall nel kernel: a sistema avviato non si possono più cambiare le regole né disabilitare il firewall. È un'ottima protezione contro la manomissione, ma ha un rovescio severo: se il ruleset congelato è sbagliato o isola il nodo, il nodo resta irraggiungibile e non riparabile da acceso, perché nessuna modifica è più ammessa. L'unico modo per rientrare è avviare in single-user (dove il securelevel torna basso), rimontare la radice in scrittura, disattivare il congelamento e ripartire.

Regola pratica: alzare il securelevel è l'ultimo passo, mai il primo. Prima si verifica che il firewall sopravviva a un reboot completo e che il nodo torni raggiungibile da solo; solo quando tutto è stabile e collaudato si valuta la sigillatura, tenendo sempre presente la via di recupero da single-user. Un firewall congelato e rotto è esattamente ciò che trasforma un piccolo errore di regole in un fuori servizio lungo e difficile da sbrogliare.

Linux (nftables)

Su Linux lo strumento aggiornato è nftables (iptables resta per i casi che richiedono le tabelle RAW e MANGLE); conviene disabilitare IPv6 se non usato (vedi la sezione IPv6 e MAC Address). Esempio default-deny:

# /etc/nftables.conf table inet filtro { chain input { type filter hook input priority 0; policy drop; ct state established,related accept iif "lo" accept tcp dport 22 ct state new accept } } doas nft -f /etc/nftables.conf

Mitigazione di DoS e DDoS

Alle regole di base si affiancano il rate limiting e il ban automatico degli IP abusivi. In pf si usano i limiti di stato con una tabella di overload; dove serve si aggiunge il blocco per paese e fail2ban, che legge i log e inserisce da sé le regole di blocco:

# /etc/pf.conf: limita le connessioni per sorgente e isola gli abusivi table <abusivi> persist block quick from <abusivi> pass in quick proto tcp to port 443 flags S/SA keep state \ (max-src-conn 100, max-src-conn-rate 15/5, overload <abusivi> flush global)

Riferimenti utili: il capitolo sui firewall del FreeBSD Handbook e una guida alle regole anti-DDoS. Firewall proprietari con HIPS (es. Comodo) offrono funzioni simili ma, essendo chiusi, non rispettano i valori di software libero di Tutanum.

Oltre il firewall: EDR e SIEM

Il firewall è il primo strato. Il passo successivo, previsto per Tutanum, è un EDR e un SIEM personalizzati che raccolgano e correlino gli eventi di rete e di sistema (regole pf o nftables, i rilevamenti, i log, i ban di fail2ban) per accorgersi degli attacchi prima che diventino compromissione. Gli avvisi vanno inoltrati fuori banda, come descritto nella sezione Monitoraggio.

Difesa dalla forza bruta

Un servizio di amministrazione raggiungibile viene provato di continuo da programmi che tentano nomi utente e password. L'autenticazione a sola chiave rende inutili quei tentativi, ma restano il rumore nei registri, il consumo di risorse e il rischio che una falla del servizio venga trovata da chi può provare all'infinito. La risposta è bandire chi insiste. Gli strumenti sono quattro, e non vanno sommati: fanno la stessa cosa in modi diversi.

pf (overload)blacklistdsshguardfail2ban
Che cos'èUna regola del firewallUn demone del sistema di base di FreeBSDUn piccolo demone in CUn'applicazione in Python
Che cosa osservaQuante connessioni apre una sorgenteGli accessi falliti che i demoni gli notificanoI registri, con riconoscitori già compilatiI registri, con espressioni regolari
Servizi copertiQualunque portaSolo i demoni che lo supportano (sshd tra questi)SSH e una decina di servizi comuniQualunque cosa scriva un registro
Codice in piùNessunoNessunoPocoMolto, più l'interprete Python
SistemiFreeBSD, OpenBSDFreeBSD, NetBSDBSD e GNU/Linux GNU/Linux, BSD
Valori del progettoIl più semplice possibileSemplice, già presenteSemplice e portabilePotente ma lontano dal KISS

La scelta per Tutanum segue la regola di aggiungere complessità solo quando serve. Il primo strato è la regola di pf, che non richiede alcun programma. Sopra si mette un solo demone: sshguard, che vede ciò che il conteggio delle connessioni non vede (tentativi lenti, utenti inesistenti) e resta piccolo e leggibile. blacklistd è l'alternativa per chi non vuole installare nulla. fail2ban si riserva al caso in cui bisogna reagire ai registri di un'applicazione qualsiasi, tipicamente su un nodo GNU/Linux.

Primo strato: pf

Chi apre troppe connessioni in poco tempo finisce in una tabella, e le sue connessioni aperte vengono chiuse. È già nel file pf.conf di esempio. La tabella la riempie il kernel, quindi funziona anche quando il securelevel ha congelato pf; il computer di amministrazione ne resta fuori, perché quattro connessioni in quindici secondi bastano a chiudere fuori anche lui.

table <bruteforce> persist block drop in quick on em0 from <bruteforce> pass in quick on em0 inet proto tcp from $admin to (em0) port ssh flags S/SA keep state pass in on em0 inet proto tcp to (em0) port ssh flags S/SA keep state \ (max-src-conn 10, max-src-conn-rate 3/15, overload <bruteforce> flush global) doas pfctl -t bruteforce -T show # chi è stato bandito doas pfctl -t bruteforce -T expire 86400 # da cron: i bandi scadono dopo un giorno

sshguard

sshguard legge il registro degli accessi, assegna un punteggio a ogni tentativo riconosciuto come attacco e, superata la soglia, inserisce l'indirizzo in una tabella del firewall. A ogni recidiva il bando si allunga, e oltre un secondo punteggio diventa permanente. Su FreeBSD la configurazione sta in /usr/local/etc/sshguard.conf (su altri sistemi in /etc/sshguard.conf).

Sul nodo il backend è quello di ipfw, non quello di pf. Dal securelevel 2 FreeBSD 15 non accetta più indirizzi nelle tabelle di pf, e il backend di pf chiude anche le connessioni (pfctl -k), altra operazione vietata: provato su FreeBSD 15.1, la tabella resta vuota. La tabella 22 di ipfw invece si riempie, e la regola che la usa sta già in ipfw.rules.

# /usr/local/etc/sshguard.conf BACKEND="/usr/local/libexec/sshg-fw-ipfw" # agisce sulla tabella 22 di ipfw FILES="/var/log/auth.log" # i registri da leggere THRESHOLD=30 # ogni tentativo vale 10: bando al terzo BLOCK_TIME=600 # primo bando di dieci minuti, poi cresce a ogni recidiva DETECTION_TIME=1800 # i punteggi si azzerano dopo mezz'ora di quiete IPV4_SUBNET=32 BLACKLIST_FILE=90:/var/db/sshguard/blacklist.db # oltre 90 punti il bando è permanente WHITELIST_FILE=/usr/local/etc/sshguard.whitelist # chi non va mai bandito # /usr/local/etc/sshguard.whitelist (un indirizzo per riga, i commenti su righe proprie) # il computer di amministrazione, non tutta la LAN: un dispositivo di casa compromesso # deve poter essere bandito 192.168.178.10 # la jail di Tor: vedi più sotto 10.0.0.2 # /etc/ipfw.rules (già presente) ipfw -q table 22 create type addr ipfw -q add 52 deny log ip from 'table(22)' to me not layer2 doas pkg install sshguard doas install -d -m 700 /var/db/sshguard doas sysrc sshguard_enable=YES doas service sshguard start doas ipfw table 22 list

blacklistd

Non legge registri: sono i demoni stessi a comunicargli ogni accesso fallito. È nel sistema di base, quindi non aggiunge codice, ma copre solo i programmi che lo supportano. Banda aggiungendo regole a un'àncora di pf: su un nodo al securelevel 2 non funziona, perché FreeBSD 15 da quel livello non accetta più regole.

# /etc/blacklistd.conf [local] # porta tipo protocollo proprietario nome tentativi durata ssh stream * * * 3 24h [remote] # il computer di amministrazione non viene mai bandito 192.168.178.10/32:ssh * * * = * * # /etc/ssh/sshd_config UseBlacklist yes # /etc/pf.conf anchor "blacklistd/*" in on em0 doas sysrc blacklistd_enable=YES doas service blacklistd start && doas service sshd restart doas blacklistctl dump -b # gli indirizzi banditi

fail2ban

fail2ban è il più flessibile: qualunque riga di qualunque registro può diventare un motivo di bando, con filtri scritti come espressioni regolari. È anche il più pesante, e un filtro scritto male è esso stesso una vulnerabilità, perché chi controlla ciò che finisce nel registro può far bandire indirizzi a scelta. Si usa solo dove gli altri non arrivano.

# /usr/local/etc/fail2ban/jail.local (mai modificare jail.conf: viene sovrascritto dagli aggiornamenti) [DEFAULT] bantime = 1h findtime = 10m maxretry = 3 bantime.increment = true # ogni recidiva allunga il bando bantime.maxtime = 1w ignoreip = 127.0.0.1/8 192.168.178.10 10.0.0.2 banaction = pf # su GNU/Linux: nftables; su un nodo al securelevel 2: ipfw [sshd] enabled = true logpath = /var/log/auth.log [nginx-http-auth] # tentativi sull'area protetta del sito enabled = true logpath = /jails/jails-data/web-data/var/log/nginx/error.log # /etc/pf.conf anchor "f2b/*" doas fail2ban-client status sshd # indirizzi banditi doas fail2ban-client set sshd unbanip 203.0.113.7

Dietro Tor e I2P il bando per indirizzo non funziona

Tutti questi strumenti ragionano per indirizzo IP. Ma un servizio raggiunto attraverso un onion service vede arrivare ogni connessione dalla jail di Tor, e uno raggiunto attraverso I2P dalla jail di i2pd. Tre tentativi falliti di uno sconosciuto bandirebbero quindi la jail stessa, cioè tutti: l'attaccante otterrebbe gratis un'interruzione del servizio. Per questo gli indirizzi delle jail tor e i2p stanno sempre nell'elenco di chi non va bandito, e per i servizi nascosti la difesa è un'altra.

  • Sola autenticazione a chiave, con pochi tentativi per connessione (MaxAuthTries 3) e un tempo breve per completare l'accesso.
  • Autorizzazione dei client dell'onion service: chi non possiede la chiave non arriva nemmeno al servizio (vedi Buone pratiche da Whonix).
  • Proof-of-work e limiti per circuito, descritti negli attacchi alla rete Tor.
  • Su I2P, l'elenco delle destinazioni ammesse.

Il bando per indirizzo resta utile solo per ciò che è esposto in chiaro, cioè, su un nodo Tutanum, l'SSH verso la rete di gestione.

Bloccare gli IP di una nazione

Bloccare un intero paese al firewall è una misura grossolana: la geolocalizzazione degli IP non è precisa, è aggirabile con VPN, proxy o Tor e rischia di bloccare traffico legittimo. Va quindi usata come misura aggiuntiva e consapevole, non come difesa principale.

Soprattutto, non va fatto espandendo i singoli indirizzi: un paese può averne decine di milioni e creare una regola di firewall per ogni IP satura memoria e tabelle, rendendo il firewall inutilizzabile. Il modo corretto è lavorare con i blocchi CIDR caricati in una tabella o in un set e bloccati da una sola regola.

1. Procurarsi i blocchi CIDR del paese

Le liste CIDR aggregate per paese sono disponibili già pronte su ipdeny (<cc> è il codice ISO del paese: it, in, us, cn...):

# OpenBSD doas ftp -o paese.zone https://www.ipdeny.com/ipblocks/data/aggregated/it-aggregated.zone # FreeBSD doas fetch -o paese.zone https://www.ipdeny.com/ipblocks/data/aggregated/it-aggregated.zone # Linux curl -fsSL -o paese.zone https://www.ipdeny.com/ipblocks/data/aggregated/it-aggregated.zone

In alternativa si possono ricavare i range da ip2location (sostituendo india con il paese) e convertirli in CIDR, ma le zone già aggregate di ipdeny evitano qualsiasi elaborazione manuale.

2. Caricare la lista nel firewall

Su un nodo Tutanum (FreeBSD o OpenBSD) si usa pf: una tabella carica l'intera lista e una sola regola la blocca.

# /etc/pf.conf table <blocca_paese> persist file "/etc/pf/paese.zone" block drop in quick from <blocca_paese> to any

Installare la lista e caricare le regole:

doas mkdir -p /etc/pf doas cp paese.zone /etc/pf/paese.zone doas pfctl -f /etc/pf.conf

Per aggiornare in seguito la tabella senza ricaricare tutto il firewall:

doas pfctl -t blocca_paese -T replace -f /etc/pf/paese.zone

Su un nodo sigillato, al securelevel 2, FreeBSD 15 non accetta più nuovi indirizzi nelle tabelle di pf: né il replace né pfctl -f funzionano a sistema avviato. La lista aggiornata si copia in /etc/pf/paese.zone e vale dal riavvio successivo, quando pf la legge prima che il securelevel salga.

Alternativa su Linux (nftables)

doas nft add table inet filtro doas nft add chain inet filtro input '{ type filter hook input priority 0; policy accept; }' doas nft add set inet filtro blocca_paese '{ type ipv4_addr; flags interval; }' doas nft add element inet filtro blocca_paese "{ $(paste -sd, paese.zone) }" doas nft add rule inet filtro input ip saddr @blocca_paese drop

Oppure con ipset e iptables:

doas ipset create blocca_paese hash:net xargs -a paese.zone -I{} doas ipset add blocca_paese {} doas iptables -I INPUT -m set --match-set blocca_paese src -j DROP

3. Verifica

Controllare quante reti sono state caricate e che il blocco sia attivo:

# pf doas pfctl -t blocca_paese -T show | wc -l # nftables doas nft list set inet filtro blocca_paese | head # ipset doas ipset list blocca_paese | head

Per contare in tempo reale i pacchetti effettivamente scartati conviene leggere i contatori del firewall (doas pfctl -s info per pf, i contatori della regola per nftables o iptables) invece di contare le singole regole.

Configurazioni di esempio

Di seguito i file di configurazione di un nodo Tutanum su FreeBSD, gli stessi a cui rimanda Tutanum Classico e con gli stessi nomi e indirizzi. I file completi e commentati si trovano nella cartella config/ del progetto. L'impianto è una difesa a due livelli: ipfw al livello 2 (ethernet, più il blocco delle impronte di scansione) e pf ai livelli 3 e 4 (IP, porte, NAT per le sole jail delle reti anonime, anti bruteforce), con i servizi di sistema in rc.conf e un DNS cifrato e anonimizzato tramite DNSCrypt.

rc.conf

Abilita ciò che serve all'host e nient'altro: ZFS, auditd, i due firewall con i loro registri, sshguard, dnscrypt-proxy, CBSD e il securelevel a 2. Il nome dell'host è generico (nodo), l'indirizzo è statico con un MAC casuale a ogni avvio, IPv6 e NTP sono spenti, e l'interfaccia lo1 ospita gli indirizzi delle jail. Tor non gira sull'host: tor_enable si imposta dentro la jail tor. Delle versioni precedenti restano corretti il refuso firewall_scrypt e le righe di pf che mancavano (pf si abilita con pf_enable, non con firewall_enable, che riguarda ipfw). blacklistd, sshguard e fail2ban si sovrappongono: per il principio KISS ne basta uno.

pf.conf

Default-deny in ingresso e in uscita, anche tra le jail, con risposta silenziosa (block-policy drop): un return confermerebbe l'esistenza del nodo e annullerebbe tcp.blackhole. Quattro scelte reggono il resto.

  • L'ordine: pf vuole macro, tabelle, opzioni, normalizzazione, traduzione e filtro in questa sequenza, e rifiuta un file che la viola. Tra le regole quick vince la prima che corrisponde, quindi i blocchi delle tabelle (sshguard, bruteforce, quarantena) stanno prima di ogni pass: messi in fondo non scatterebbero mai.
  • Il loopback non si salta: le jail hanno indirizzi propri su lo1, e il kernel instrada il traffico verso di loro attraverso lo1 stessa (verso l'indirizzo dell'host sulla LAN, invece, attraverso lo0). Un set skip su una delle due annullerebbe l'isolamento tra un servizio e l'altro.
  • Escono solo tor e i2p: il NAT riguarda soltanto le loro due jail e le marca con un'etichetta, perché dopo il NAT l'indirizzo di origine è quello di em0 e il filtro in uscita non saprebbe più distinguerle.
  • L'host esce solo con dnscrypt-proxy: la regola guarda l'utente del processo (_dnscrypt-proxy), indicato con il suo UID fisso, 978: pfctl risolve i nomi mentre carica il file, e con il nome il file verrebbe rifiutato finché il pacchetto non è installato. Aggiornamenti e git passano dalla jail tor; per le rare eccezioni c'è una tabella manutenzione, vuota per il resto del tempo.
  • pf è la politica fissa: dal securelevel 2 FreeBSD 15 non accetta più regole né indirizzi nelle tabelle, e non chiude connessioni. Provato su FreeBSD 15.1. Ciò che cambia a sistema avviato (sshguard, quarantena dell'EDR, esche) vive nelle tabelle di ipfw, che a quel livello restano modificabili e, a differenza di pf, fermano subito anche le connessioni già aperte.

Restano il blocco di IPv6, la normalizzazione e il blocco delle combinazioni di flag TCP illecite (anti OS fingerprint), con la maschera corretta: la bozza usava WEVAPRSF, ma la lettera V non è un flag TCP valido. I flag validi in pf sono F, S, R, P, A, U, E, W, quindi la maschera di tutti i flag è WEUAPRSF.

# traduzione: soltanto tor e i2p, marcate per il filtro in uscita nat on $ext_if inet from $j_tor to any tag TOR -> ($ext_if) nat on $ext_if inet from $j_i2p to any tag I2P -> ($ext_if) # banditi: prima di qualunque pass (la tabella la riempie il kernel) block drop in quick on $ext_if from <bruteforce> # anti OS fingerprint (maschera dei flag corretta) block drop in log quick on $ext_if proto tcp flags SF/SF block drop in log quick on $ext_if proto tcp flags /WEUAPRSF # SSH solo dalla LAN, con tabella di overload persistente pass in quick on $ext_if inet proto tcp from $lan to $nodo port ssh flags S/SA keep state \ (max-src-conn 10, max-src-conn-rate 3/15, overload <bruteforce> flush global) # l'host esce soltanto con dnscrypt-proxy, le jail soltanto se marcate pass out quick on $ext_if inet proto tcp from $nodo to any user 978 modulate state # _dnscrypt-proxy pass out quick on $ext_if proto tcp tagged TOR modulate state

ipfw.rules

Filtro di livello 2: lascia passare a livello ethernet soltanto ARP e IPv4, scarta le impronte TCP tipiche delle scansioni e affida il resto del livello 3 a pf. Tiene inoltre le tabelle che cambiano a sistema avviato: quarantena per l'EDR, 22 per sshguard, esche per l'honeypot e mai_bloccare, letta da /etc/ipfw.mai_bloccare. Il valore di ogni voce è l'ora di inserimento, che serve a farla scadere. ipfw esamina i frame ethernet solo con net.link.ether.ipfw=1, e da quel momento ogni pacchetto attraversa le regole due volte: per questo ogni regola dice se vale per il frame (layer2) o per il pacchetto IP (not layer2). Le versioni precedenti usavano una sintassi allow ether ... che ipfw non conosce (il livello 2 si scrive con layer2, mac e mac-type) e avevano il default-deny di livello 2 in testa, dove bloccava tutta la rete; erano state tolte anche tre regole inesistenti (un limit su ether type, un deny ether type 0x0801 per lo STP, che non ha un ethertype, e un maxfrag 1500 per i jumbo frame, che sono una questione di MTU) e la tabella per fail2ban, superflua con sshguard.

dnscrypt-proxy.toml

DNS cifrato e anonimizzato: solo DNSCrypt, niente DoH (che passerebbe da pochi grandi provider), risolutori che non registrano e non filtrano, DNSSEC richiesto e instradamento tramite relay (anonymized_dns) per tutti i server, con la rotta '*': un server senza rotta verrebbe interrogato direttamente e vedrebbe l'indirizzo del nodo. Ascolta su 127.0.0.1:53 e sull'indirizzo dell'host visto dalle jail, e non tiene registri delle richieste: un elenco di ogni nome risolto contraddirebbe la scelta di non registrare i visitatori. La bozza originale veniva da un'app Android, con percorsi in /data/user/0/pan.alexander.tordnscrypt.stable/..., riportati a percorsi di sistema; i file facoltativi (inoltro, cloaking, portali) restano commentati, perché se indicati e assenti il demone non parte.

Servizi esposti

Ogni servizio in ascolto su una porta è una superficie di attacco e un possibile punto di deanonimizzazione: una versione che rivela una vulnerabilità, un banner che identifica il sistema, un comportamento che distingue il nodo dagli altri. Il principio guida è quindi semplice: meno servizi si espongono, meglio è. Un servizio non installato non può essere attaccato.

Da questo discendono alcune regole pratiche: attivare solo ciò che serve davvero e disattivare il resto; firewall in default-deny, come visto nella sezione Firewall; e, quando possibile, esporre i servizi come eepsite I2P o come onion service invece che sul clear web, così che l'indirizzo IP del nodo non sia mai pubblico. Dove l'esposizione sul clear web è inevitabile, la si fa uscire attraverso Tor e la si protegge come descritto qui sotto.

Forge: il server di repository

Un forge è la piattaforma che ospita i repository di codice e, spesso, l'integrazione continua. È un servizio comodo ma pesante da esporre, quindi la scelta del prodotto conta. Confrontando le soluzioni libere più diffuse:

  • Forgejo: fork comunitario di Gitea sotto licenza copyleft, leggero, scritto in Go, facile da autoospitare e con lavoro in corso sulla federazione (ForgeFed). È tra le soluzioni più in linea con i valori di Tutanum: software libero, comunitario, leggero e decentralizzabile.
  • Gitea: progenitore di Forgejo, altrettanto leggero. La governance è però passata a una società commerciale, ragione del fork: resta valido, ma Forgejo è preferibile per garanzie di indipendenza.
  • GitLab CE: molto potente ma pesante, composto da numerosi componenti e pensato per scalare in contesti aziendali. È in contrasto con l'antiscalabilità e con la leggerezza che Tutanum persegue, oltre a trascinare funzioni che diventano superficie di attacco.
  • cgit e Gitolite: minimalismo estremo. cgit è una semplice interfaccia web in sola lettura, Gitolite gestisce gli accessi via SSH e chiavi. Nessuna CI integrata, ma superficie ridottissima: la scelta giusta quando serve soltanto pubblicare o condividere codice.
  • SourceHut: suite minimale e molto unix, incentrata sulla posta elettronica e sul software libero, autoospitabile. Filosoficamente vicina a Tutanum, con una curva di apprendimento più ripida.

Tutti i forge elencati restano però dei server centrali da esporre. Un passo oltre, perfettamente allineato ai valori del progetto, è iop: uno strumento di collaborazione sul codice peer to peer e anonimo, scritto in Rust, che instrada i repository Git direttamente tra i collaboratori attraverso i tunnel cifrati di I2P (tramite il bridge SAM del router locale), eliminando del tutto il server di repository centrale. Nello spirito di Radicle ma nativo su I2P, adotta una politica fail-closed (si ferma invece di ripiegare sul clear web), identità crittografiche Ed25519 e profili di privacy configurabili (paranoid, balanced, performance). È la direzione più coerente con Tutanum: nessun punto centrale, anonimato per costruzione e rete I2P come trasporto ufficiale.

I due approcci non si escludono, e ciascuno ha il proprio terreno. Il server di repository va bene per i dispositivi della propria rete, che da lì si aggiornano. iop serve dove quel server non arriva: tra server ridondati che non stanno sulla stessa rete, per i dispositivi che si portano fuori casa e come alternativa a BitTorrent, con il vantaggio che, usando Git, tutto ciò che viene condiviso è versionato e tracciato.

In sintesi: iop quando si vuole fare a meno del server di repository e condividere i file tracciati con Git direttamente tra i nodi, in modo anonimo per costruzione; Forgejo per un forge completo ma sobrio; cgit o Gitolite quando basta esporre il codice; evitando in ogni caso le piattaforme pesanti e orientate alla scalabilità.

Codeberg e le piattaforme ospitate da altri

Tra i forge pubblici, Codeberg è quello che più somiglia a Tutanum sulla carta: è gestito da un'associazione tedesca senza scopo di lucro, gira su Forgejo, ospita solo software libero, non traccia e non vende nulla. Per questo è stato usato anche in questo progetto. C'è però una ragione per non farne il proprio punto d'appoggio, ed è una ragione di struttura prima che di merito.

Codeberg prende posizioni politiche esplicite. Nell'articolo We stay strong against hate and hatred, del 12 febbraio 2025, scritto dopo una campagna di molestie contro alcuni progetti ospitati, l'associazione dichiara di opporsi a ogni discriminazione, definisce la diversità un valore per il software libero e attribuisce l'accaduto all'estrema destra: "Codeberg is currently suffering from hate campaigns due to far-right forces". È una linea dichiarata. Il progetto Tutanum la legge come una posizione di sinistra e woke e, per questa via, come un sostegno indiretto all'Agenda 2030, che l'articolo non nomina in modo esplicito. La si può condividere o no: il punto è un altro.

  • Una piattaforma con una linea decide chi ospitare: i suoi termini d'uso le permettono di rimuovere progetti e account che giudica incompatibili. Chi ospita lì il proprio lavoro lo affida al giudizio di qualcun altro, oggi e dopo ogni futuro cambio di orientamento.
  • Resta un punto centrale: un'associazione, una giurisdizione, un insieme di server. Può essere messa sotto pressione, attaccata o chiusa, come ogni forge centralizzato.
  • Conosce i metadati: chi collabora con chi, quando e da quale indirizzo.

Vale per Codeberg come per GitHub o GitLab, da cui si distingue in meglio per tutto il resto. Un progetto che ha tra i propri valori la decentralizzazione e la resistenza alla censura non dovrebbe dipendere dall'approvazione di alcuna piattaforma, qualunque ne sia il colore. La regola pratica è questa.

  • La copia che conta sta sui propri nodi, distribuita con iop o servita dal proprio forge.
  • Una piattaforma pubblica è al massimo uno specchio: serve a farsi trovare, e la sua scomparsa non deve costare nulla.
  • Ci si arriva attraverso Tor, con un'identità e una chiave SSH usate solo lì.
# ~/.ssh/config: una chiave dedicata, e solo attraverso Tor Host codeberg.org User git IdentityFile ~/.ssh/id_ed25519_specchio IdentitiesOnly yes # non offre le altre chiavi ProxyCommand nc -X 5 -x 10.0.0.2:59353 %h %p # SOCKS della jail di Tor # l'impronta della chiave del server si confronta con quella pubblicata nella documentazione di Codeberg ssh -T git@codeberg.org # lo specchio riceve, non comanda: si spinge soltanto, dalla copia sui propri nodi git remote add specchio git@codeberg.org:utente/progetto.git git push --mirror specchio

Pipeline di sicurezza

Il codice e le immagini prodotte vanno analizzati prima di essere pubblicati o messi in esecuzione. Una pipeline difensiva combina strumenti liberi che coprono fasi diverse, bloccando la pipeline stessa quando emergono problemi di gravità elevata:

  • Gitleaks: cerca segreti e credenziali nei file e nell'intera storia dei commit.
  • Semgrep: analisi statica (SAST) multilinguaggio basata su regole, per schemi di codice vulnerabili.
  • Bearer: analisi statica orientata ai dati sensibili e alla privacy, utile per individuare dove fluiscono le informazioni personali.
  • Trivy: scansione delle vulnerabilità di dipendenze, file di configurazione, infrastruttura come codice e immagini.
  • Grype: scansione delle vulnerabilità a partire da un SBOM o da un'immagine, ben abbinato a Syft che il SBOM lo genera.

Quando il prodotto è un container, dopo il build dell'immagine Docker o OCI si esegue Trivy direttamente sull'immagine, per intercettare le vulnerabilità introdotte dai layer di base e dalle dipendenze di sistema. Uno scheletro di pipeline:

# 1. Segreti nella storia del repository gitleaks detect --source . --redact # 2. Analisi statica del codice (SAST) semgrep scan --error --config auto bearer scan . # 3. Vulnerabilita' nelle dipendenze e nella configurazione trivy fs --scanners vuln,secret,misconfig --severity HIGH,CRITICAL . grype dir:. --fail-on high # 4. Build dell'immagine e scansione dell'immagine stessa docker build -t tutanum/servizio:ci . trivy image --severity HIGH,CRITICAL --exit-code 1 tutanum/servizio:ci

Runner e calcolo distribuito

I runner che eseguono la pipeline sono macchine di Tutanum, non servizi esterni di terzi: eseguire la CI su infrastruttura altrui significa consegnare codice, segreti e tempi di lavoro a un fornitore. I runner vanno isolati in container o jail effimeri, senza segreti persistenti e con rete limitata al necessario.

Il carico, però, non deve spingere verso un cluster che scala in modo elastico, cosa in contrasto con l'antiscalabilità: l'idea è piuttosto una federazione di nodi indipendenti e sostituibili. Alcune soluzioni, tutte con software libero:

  • Runner distribuiti: registrare più agenti su macchine diverse e fidate (Forgejo Runner, Woodpecker CI con più agent), ciascuno autonomo. Se uno cade, gli altri proseguono.
  • Compilazione distribuita: distcc o icecream (icecc) distribuiscono la compilazione C e C++ su più nodi della rete, con sccache come cache condivisa dei risultati.
  • Build riproducibili distribuite: i remote builder di Nix o l'offload di GNU Guix delegano le compilazioni ad altri nodi mantenendo la riproducibilità, tema ripreso nella sezione Verifica e integrità del software.

Il risultato è un calcolo ripartito fra pari che restano singolarmente spegnibili, non un servizio centralizzato che cresce senza limiti.

SSH

SSH è quasi sempre il primo servizio di amministrazione ed è costantemente sotto attacco automatizzato. Va ridotto all'osso: sola autenticazione a chiave, niente accesso diretto come root, elenco esplicito degli utenti ammessi, algoritmi moderni e, se possibile, esposizione solo attraverso I2P, un onion service o una VPN fidata anziché sul clear web.

# /etc/ssh/sshd_config (estratto difensivo) PermitRootLogin no PasswordAuthentication no KbdInteractiveAuthentication no PubkeyAuthentication yes AllowUsers amministratore MaxAuthTries 3 LoginGraceTime 20 X11Forwarding no AllowAgentForwarding no

Il rate limiting dei tentativi si ottiene con il firewall (la tabella di overload di pf vista nella sezione Firewall) o con strumenti come sshguard, evitando di affidarsi alla sola robustezza delle chiavi.

Web server

Vale di nuovo il minimalismo: meglio un server piccolo e verificabile come httpd di OpenBSD (che sfrutta pledge e unveil per autolimitarsi) o nginx, senza i moduli non necessari di server più grandi. Vanno disattivati i banner di versione, attivati TLS moderno e le intestazioni di sicurezza, e i processi vanno separati e confinati (chroot). Come per gli altri servizi, l'esposizione ideale è come eepsite I2P o onion service.

# nginx: ridurre l'impronta e irrobustire le intestazioni server_tokens off; add_header X-Content-Type-Options nosniff; add_header X-Frame-Options DENY; add_header Referrer-Policy no-referrer; add_header Strict-Transport-Security "max-age=31536000" always;

Trasferimento file: SFTP, mai FTP

FTP trasmette credenziali e dati in chiaro e usa connessioni dati separate che mal si conciliano con firewall e NAT: va escluso. La scelta corretta è SFTP, che non è FTP ma un sottosistema di SSH, quindi già cifrato e autenticato sullo stesso canale sicuro, senza aprire altre porte. Gli utenti dedicati al solo trasferimento vanno confinati in una cartella (chroot) e privati della shell.

# /etc/ssh/sshd_config: SFTP confinato, senza shell Match Group sftp ChrootDirectory /srv/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no

Tor

Con il nome Tor si indicano tre elementi distinti:

  • Tor come rete anonima.
  • Tor Browser, ovvero il browser rilasciato dal Tor Project che oltre ad integrare diverse impostazioni che impediscono il tracciamento dell'utente, permette anche di mascherare il proprio IP dietro ad altri nodi, proprio usando la rete tor.
  • Tor Project, il progetto guida per lo sviluppo della rete tor e dell'omonimo browser.

L'anonimato su internet esiste?

In seguito alla proposta di mettere la carta di identità sui social, è importante una riflessione sull'effettiva esistenza dell'anonimato online.

Differenza tra privacy, sicurezza e anonimato

La privacy si riferisce alla capacità di controllare la divulgazione delle proprie informazioni personali. In pratica, questo significa poter decidere quando e come le tue informazioni personali vengono condivise o esposte su Internet. La privacy è tutelata da regolamenti UE e qualora si venissero richiesti dei dati è necessario che il servizio notifichi l'utente, seppur spesso utilizzino i nudge per fare accettare all'utente di cedere i propri dati.
L'anonimato invece riguarda la capacità di non fornire alcuna informazione a priori rispetto alla propria attività online, siano essi dati riconducibili o meno alla propria utenza. Ad oggi non esiste alcuna legge che tuteli il diritto all'anonimato. La sicurezza è invece relativa alla possibilità di compromissione di un sistema presso la quale sono conservati dei dati o dei metadati relativi alla propria utenza.

Proxy, VPN e relativi problemi

I proxy sono dei server che si pongono tra il sito di destinazione e chi fa la richiesta in modo da garantire l'anonimato, poiché l'indirizzo IP di chi fa le richieste rimane quello del server proxy. I server proxy utilizzano prevalentemente HTTP e non HTTPS, pertanto le connessioni non sono cifrate. Le VPN sono delle reti vere e proprie a cui l'utente si collega per potere usufruire di servizi messi a disposizione dal fornitore del servizio, oppure comunque per garantire l'anonimato esponendo pertanto solo l'IP del server della VPN. È un servizio quasi sempre a pagamento e per questo solitamente richiede dati specifici, cosa che permette di non garantire una sicurezza sulla privacy. Seppur l'ISP (Internet Service Provider, il fornitore di internet) non possa spiare le connessioni cifrate che passano tramite proxy o VPN, è possibile che i dati presenti sui relativi server vengano ceduti o addirittura venduti a terzi. Per questo motivo è necessario l'utilizzo di nodi anonimi presso la quale non lasciare tracce delle richieste effettuate. I black hat al fine di non lasciare tracce compromettono solitamente con dei malware dei sistemi di gente comune al fine di renderli ubbidienti e pronti all'uso, mascherando di fatto il proprio IP con quei dispositivi, realizzando ciò che prende il nome di botnet.

Tor

Tor (non il browser ma il servizio) si pone come soluzione alternativa alle botnet in quanto presenta un algoritmo basato su una cifratura a strati e una rete di nodi volontari che si collegano tra loro offrendo un mascheramento degli IP multilivello, una protezione dagli attacchi DDoS e una cifratura sulle richieste effettuate, rendendola una rete difficilmente compromessa. È una rete sviluppata dalla US Navy Research Laboratory negli anni '90 ma che si è ad oggi evoluta per garantire l'anonimato su internet. Ad oggi è stato dimostrato tuttavia che l'anonimato può essere compromesso usando nodi malevoli, questione che richiede una corretta configurazione del servizio permettendo di evitare di passare per bridge o per exit node che possono compromettere l'anonimato. La configurazione avviene prevalentemente per mezzo del file torrc, attualizzabile anche su Orbot (l'app di Tor per Android). Pubblicheremo nei prossimi post come configurare correttamente il torrc per garantire un anonimato più robusto di quello garantito già di default dal software.

Conclusioni

L'anonimato esiste ed esiste anche la privacy e si possono quantificare misurando il livello di sicurezza dei sistemi utilizzati, infatti l'anonimato non è assoluto o un processo tutto o nulla, ma consiste una serie di strategie di mitigazione per rendere sempre più difficile l'essere scoperti. Si tratta di accorgimenti che seppur non garantiscano una totale protezione nel caso di indagine a carico delle forze dell'ordine, possono servire per evitare la profilazione da parte delle multinazionali.

Architettura di Tor

L'architettura di Tor (The Onion Router) si basa sulla cifratura a strati e sul routing attraverso tre nodi principali: guard (o entry), middle ed exit. Ciascun nodo conosce solo il segmento di rete precedente e quello successivo.

Connessione verso il clear web

  1. Circuito a 3 salti: il client scarica l'elenco dei nodi pubblici e stabilisce un percorso cifrato.
  2. Cifratura: i dati vengono cifrati tre volte, con le chiavi di guard, middle ed exit.
  3. Uscita: il guard node vede l'IP reale dell'utente, il middle node fa da ponte, l'exit node decifra l'ultimo strato e inoltra la richiesta in chiaro (o via HTTPS del sito) verso la destinazione finale. L'IP visibile al sito web sarà quello dell'exit node.
UtenteGuardMiddleExitSitovede l'IP realevede la destinazione
Circuito a 3 salti verso il web in chiaro: l'exit node vede la destinazione, non il client.

Connessione verso gli hidden service

La connessione verso i domini .onion non prevede nodi di uscita verso l'internet pubblico: è interamente cifrata end-to-end su 6 salti, 3 del client e 3 del servizio nascosto, che si uniscono a metà strada presso un rendezvous point concordato tramite un introduction point pubblico. Il mutuo anonimato è garantito e il traffico non lascia mai la rete Tor.

ClientGuardMiddleHiddenServiceGuardMiddleRendezvousPoint
Hidden service: i circuiti del client e del servizio (3 salti ciascuno) si incontrano al rendezvous point; niente exit.

Tor browser: problema di privacy

Tor browser è un browser basato su Mozilla FIrefox, nato, per garantire la privacy e l'anonimato degli utenti utilizzando la rete Tor, nel dicembre 2006 presso l'U.S. Naval Research Laboratory, mentre oggi è mantenuto dall'organizzazione senza scopo di lucro Tor Project, supportata da donazioni e volontari.

Come funziona

Tor (The Onion Router) è un sistema che fornisce anonimato online attraverso una rete di nodi volontari. Quando un utente utilizza Tor Browser o un altro browser configurato con tor, la connessione attraversa una serie di nodi crittografati distribuiti in tutto il mondo, dove ciascun nodo rimuove poi uno strato di crittografia per rivelare solo il successivo nodo nella catena. Questo processo a strati, chiamato "a cipolla" permette di ottenere l'anonimato delle richieste fatte ai siti web. La connessione inizia da un "nodo di ingresso", passa attraverso nodi intermedi e raggiunge infine un "nodo di uscita" (exit node), rendendo difficile la tracciabilità dell'utente originale.

Tor browser contatta segretamente Mozilla

E qui veniamo al cavillo rispetto alla privacy, che di fatto non è stato ad oggi ancora risolto. In base a questa problematica da cui è poi ne è derivato questo post, ogni tanto partono dei pacchetti diretti verso i server di Mozilla (firefox.settings.services.mozilla.com), la casa produttrice di Firefox, TorBrowser deriva da Firefox, è una fork. L'attenzione è stata poi traviata verso questioni di altra natura e questa problematica rimane ad oggi ancora irrisolta, seppur la segnalazione principale sia stata chiusa. Da quanto è stato possibile riscontrare, potrebbe essere coinvolto il software Kinto, una piattaforma di immagazzinamento di dati, open source, sviluppata da Mozilla, progettata per semplificare la gestione e la sincronizzazione dei dati tra applicazioni e dispositivi. Dal sito di supporto di Mozilla il fatto viene giustificando asserendo che l'host viene contattato per sapere se sono stati attuati dei databreach nei dati inseriti dall'utente. Rimane che un browser come Tor che dovrebbe garantire l'anonimato invia dei pacchetti ad un'azienda che collabora con i motori di ricerca proprietari e non tutela al massimo la privacy dei suoi utenti.

Soluzioni

Come soluzione ci sarebbe questa piccola modifica da apportare che puoi visualizzare cliccando qui per risolvere la problematica, da attuare tuttavia ogni volta che si andrà ad aggiornare il browser. La modifica si può effettuare solo dal computer a causa della diversa disposizione dei file e del codice dell'applicazione in questione. In alternativa la via migliore, sempre per il computer, rimane usare il servizio di tor più un browser orientato realmente verso la privacy e l'anonimato come IceCat o LibreWolf, insieme a tutte le estensioni utili per limitare la violazione della propria privacy e del proprio anonimato. La rete tor non è impiegabile per tutti i siti, poiché molti per funzionare necessitano di accedere appositamente ai vostri dati, inoltre molti siti e piattaforme restituiscono "too many requests" a chi usa la rete tor. Un altro caso è quello dei siti che integrano servizi di captcha offerti da Cloudflare, il quale non permette di utilizzare tor e attua pure un attacco "man in the middle" tra il dispositivo e il server che è stato contattato.

Conclusioni

La sicurezza informatica non è certamente una questione semplice, ma non per questo bisogna considerarsi già sconfitti in partenza. La privacy e l'anonimato sul web vengono da sempre ostacolate dal sistema, per cui per tutelarsi occore rimanere sempre aggiornati.

Chi ci spia: i 14 eyes

I 14 occhi, sono un'alleanza di paesi impegnati nella condivisione di informazioni tra le intelligence.

Storia

Con l'avvento dei computer e della radio è diventato sempre più importante il fronte della guerra dell'informazione, perché era importante arrivare a conoscenza dei piani del nemico per poterne anticipare le mosse.
Le alleanze di sorveglianza sono iniziate durante la seconda guerra mondiale con i 5 eyes, abbreviati anche a FVEY, tra USA, UK, poi estesa a Canada, Nuova Zelanda e Australia. L'alleanza negli anni si è mantenuta e si è estesa ai 9 eyes, con l'aggiunta di Norvegia, Olanda, Francia e Danimarca, fino ad arrivare ai 14 eyes, con Germania, Belgio, Italia, Svezia e Spagna.
Il Giappone viene considerato come un sesto occhio rispetto ai 5 originali, ma non è ufficialmente riconosciuto come membro dell'alleanza, pur mantenendo stretti rapporti di condivisione di dati con le intelligence.
Tutto ciò è trapelato dal caso datagate, sorto con i dataleak di Edward Snowden nel 2013.

Chi sono le intelligence

Sono le cosiddette agenzie di spionaggio e dispongono di una classificazione specifica per la raccolta dei dati:

  • COMINT: relativa alle comunicazioni.
  • ELINT: relativa all'elettronica.
  • FININT: relativa alla finanza.
  • HUMINT: relativa all'ingegneria sociale.
  • IMINT: relativa all'analisi dei media.
  • SIGINT: relativa all'intercettazione di segnali.
  • TECHINT: relativa agli equipaggiamenti delle forze armate.
  • OSINT: relativa al materiale open source.
  • ACINT: relativa alle analisi acustiche.
  • MASINT: relativa a metodi non convenzionali.

A livello europeo c'è l'Europol, a livello internazionale c'è l'Interpol, mentre qui in Italia abbiamo l'AISI (Agenzia Informazioni e Sicurezza Interna) e l'AISE (Agenzia Informazioni e Sicurezza Esterna), analoghe all'FBI e alla CIA statunitensi.
Al vertice del comando delle intelligence vi è il presidente del consiglio dei ministri della repubblica italiana, designabile con un'autorità delegata. Al di sotto si trovano il DIS (Dipartimento delle informazioni per la sicurezza), il COPASIR (Comitato Parlamentare per la Sicurezza della Repubblica) e il CISR (Comitato Interministeriale per la Sicurezza della Repubblica). Dal 2021 è stato inoltre istituita l'ACN (Agenzia per la cybersicurezza nazionale).
Queste oltre ai gruppi specifici presenti nelle forze armate. A livello europeo ci sarebbero da citare anche l'ENISA, l'ECCC e l'NCC.

Cosa fanno

Alcune di queste intelligence, come trapelato dal caso datagate, utilizzano programmi di sorveglianza di massa specifici. Probabilmente ne sono stati creati di altri, più performanti e probabilmente dotati di tecnologia quantistica e di intelligenza artificiale.
Citiamo tuttavia qui quelli più famosi emersi nel 2013:

  • PRISM: permette di sferrare attacchi e di raccogliere dati su scala mondiale (NSA, GCHQ, ASD).
  • XKeyscore: permette di analizzare i dati fornendo statistiche (NSA, ASD, GCSB).
  • Tempora: raccolta massiva di informazioni tramite intercettazioni per poterle decifrare in un secondo momento (GCHQ, NSA).
  • MUSCULAR: collezionatore massivo di dati (GCHQ, NSA).
  • STATEROOM: progetto di intercettazione radiofonica che comprende i firmatari dell'accordo UKUSA e i membri della rete ECHELON (ASD, CIA, CSE, GCHQ, NSA).

Conclusioni

Tutti gli strumenti che inizialmente gli Stati hanno usato per la loro guerra dell'informazione gli uni contro gli altri oggi trovano un nuovo utilizzo, ed è la lotta al dissenso, alla controinformazione. Infatti è solo di un anno e mezzo fa la notizia nella quale trapeló che il COPASIR stava indagando sui canali telegram di controinformazione, e se andiamo indietro di ancora un anno troviamo una cosa simile fatta dall'associazione MESIT. Il WEF ha dichiarato di considerare la controinformazione come il secondo più grande rischio mondiale perché è una minaccia alla legittimità dei loro governi, dichiarando che il primo sono le precipitazioni estreme, ma poiché quella del clima è una farsa, di fatto siamo i primi.

Configurare torrc

Qui di seguito verranno indicati i dettagli su come configurare ad hoc il file torrc.

Dove si trova il file torrc

Modificare il file con un editor di testo:

  • GNU Linux: /etc/tor/torrc
  • *BSD/MacOS: /usr/local/etc/tor/torrc (o in alternativa $HOME/.torrc)
  • Windows: %appdata%\Roaming\tor\torrc
  • Android/iOS: a quanto abbiamo riscontrato manualmente seguendo queste guide (1,2), nell'archivio apk delle applicazioni non è più presente il file torrc per Orbot e per Tor Services, quindi il consiglio è quello di modificare le impostazioni direttamente dall'app di Orbot, scaricabile da F-Droid abilitando il repository del The Guardian Project. Sconsigliamo l'utilizzo di Tor Browser per Android.

Torrc consigliato

Installare obfs4 (1,2) e poi modificare il file torrc come segue:

RunAsDaemon 0 AvoidDiskWrites 1 AutomapHostsOnResolve 1 AutomapHostsSuffixes .exit, .onion SOCKSPort 59353 IsolateSOCKSAuth IsolateClientAddr IsolateClientProtocol IsolateDestAddr IsolateDestPort HardwareAccel 1 Schedulers Vanilla TestSocks 1 AllowNonRFC953Hostnames 0 WarnPlaintextPorts 23,109,110,143,80 ClientRejectInternalAddresses 1 ClientOnly 1 ExitPolicy reject *:* ExitPolicy reject6 *:* VirtualAddrNetwork 10.192.0.0/10 ConnectionPadding 1 ReducedConnectionPadding 0 UseEntryGuards 1 EnforceDistinctSubnets 1 FascistFirewall 0 NewCircuitPeriod 30 MaxCircuitDirtiness 600 DormantCanceledByStartup 1 CircuitsAvailableTimeout 86400 ClientUseIPv4 1 ClientUseIPv6 0 UseBridges 1 ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed

Nel file non ci sono ExcludeNodes, ExcludeExitNodes né StrictNodes. Escludere i paesi che ospitano la maggior parte dei relay (Stati Uniti, Germania, Paesi Bassi, Francia, Regno Unito, Canada) toglie al client gran parte della banda della rete: i guard possibili diventano pochi, il client si distingue da quasi tutti gli altri e un onion service rallenta. Il Tor Project lo sconsiglia, e la protezione che promette, contro un avversario che controlla i relay di un paese, è minore di quella che toglie, perché un avversario capace sceglie dove collocarli. Chi vuole comunque escludere qualcosa si limita a pochi paesi, per esempio il proprio per il guard, sapendo che anche questa scelta rende riconoscibili.

Modificare quest'ultima riga con il percorso corretto dell'eseguibile.
Alla fine di questo file dovranno essere aggiunti i bridge (ne consigliamo 3) reperibili da qui: iat1, iat2. Per completezza riportiamo qui anche gli iat1 e iat2 che passano dai 14 occhi: iat1, iat2.
Esempio:

Bridge obfs4 37.136.134.70:3876 B7D366ECA3443481C1F4B774E50C2DBA6D7948CE cert=BeYU8A5nw3fTRxA8DphYvQrex3nV8StK3wG6/ZbFpmliJymdzAEafGdiD/zDw3wKIdJpLQ iat-mode=2

Non è possibile fidarsi di nessun bridge, ma è possibile ad ora solo mitigare. Avere altre scelte che non passano presso i 14 occhi è sicuramente meglio, ma nessuna garanzia esiste: Google e Cloudflare sono dappertutto, anche in Romania e Polonia, non si vanno ad escludere Rogue Bridge posizionati ovunque.

Cosa fa

  1. Per ogni sito ci sarà un IP diverso, un circuito nuovo ogni tot tempo, cosa che rende molto difficile tracciare l'utente.
  2. Il bridge è un relay non presente nell'elenco pubblico di Tor a cui ci si collega per fare in modo di aggiungere livelli di anonimato aggiuntivi, usando più nodi e un protocollo chiamato obfs4. Dato che non è possibile sapere chi possiede il bridge, impostare la funzione iat-mode su 2 (non è indicato di settarlo di default, e il reale guadagno in termini di privacy è discusso, come si approfondisce più avanti con la posizione di Förster). Con questa impostazione andremo a suddividere i pacchetti che invieremo al server in dimensioni variabili.
  3. Eliminare i server relativi ai 14 occhi, nel caso faccia fatica a connettersi aggiungere agli exit node da escludere Israele, USA, UK, Australia, Canada, Italia, Spagna, Vaticano, Russia, Cina e India.
  4. Disabilita IPv6, in quanto è possibile risalire al Mac Address del bridge.

Leggere il manuale di Whonix per una configurazione più personalizzata.

Conclusioni

Eludere i governi, le istituzioni e i sistemi di spionaggio mondiale, non è una passeggiata, ma ci si può provare conoscendo la tecnologia che abbiamo tra le mani tutti i giorni.
Le configurazioni fornite vanno a coprire le vulnerabilità segnalate in questi 3 link: (1, 2, 3).
Per un ulteriore verifica della validità degli exit node consigliamo questo tool.

Buone pratiche da Whonix

Whonix è il progetto che ha documentato più a fondo come far girare Tor su una macchina dedicata. Molte delle sue indicazioni nascono per una postazione di lavoro, ma quelle che seguono valgono tali e quali per un nodo che ospita servizi.

I guard non si toccano

La pagina sui guard d'ingresso è netta: forzarne la rotazione più spesso di quanto faccia Tor è pericoloso, per tre ragioni.

  • Ogni nuovo guard è un'altra occasione di sceglierne uno malevolo, e quindi di subire una correlazione.
  • Ogni cambio fa attraversare al traffico altri sistemi autonomi e altri punti di interscambio, alcuni dei quali possono essere sotto osservazione.
  • L'insieme dei guard usati nel tempo è un'impronta: pochi altri utenti hanno la stessa sequenza.

Un avversario può anche provocare la lentezza, proprio sperando che l'operatore cambi guard a mano. La scelta più sicura è sopportare le prestazioni scarse e attendere la rotazione naturale. In pratica: il file state di Tor si conserva nei backup e si riporta nella nuova jail quando la si ricostruisce.

C'è un'eccezione, che riguarda i dispositivi che si portano fuori casa. Un portatile che usa gli stessi guard a casa e altrove permette a chi osserva entrambe le reti di riconoscere la stessa persona, come farebbe un indirizzo MAC. Per questi dispositivi conviene tenere uno stato di Tor distinto per ogni luogo, oppure usare bridge diversi, e randomizzare l'indirizzo MAC.

La jail di Tor fa solo Tor

Sul gateway di Whonix non gira nient'altro che Tor, e la ragione si applica alla jail di Tor di Tutanum: chi la compromette conosce l'indirizzo IP reale del nodo, tutte le destinazioni e l'intero traffico dei servizi onion. Nessun altro programma va installato lì. Due opzioni di torrc la irrobustiscono ancora.

ConnectionPadding 1 # padding verso il guard: ostacola l'analisi dei flussi fatta dal fornitore di rete Sandbox 1 # solo Linux (seccomp): incompatibile con obfs4, meek e Snowflake

Un firewall che conosce solo Tor

corridor è un gateway che non fa da proxy ma da filtro: lascia uscire soltanto le connessioni dirette a relay di Tor, e con i bridge soltanto quelle verso i bridge configurati. È una rete di sicurezza contro le fughe in chiaro, con un limite che i suoi autori dichiarano: non impedisce a un malware di scoprire l'indirizzo pubblico. Con pf lo stesso principio si ottiene con una tabella.

# /etc/pf.conf: dal nodo si esce solo verso i propri bridge (o guard), tutto il resto è una fuga table <ponti> persist file "/etc/pf.ponti" block drop out log on em0 all pass out on em0 proto tcp from (em0) to <ponti> modulate state

Onion service

Dalla pagina sugli onion service e da quella sulla scelta di dove ospitarli:

  • Ospitare in casa, su hardware proprio: su un VPS il fornitore può leggere chiavi e dati senza toccare fisicamente la macchina. È la scelta di fondo di Tutanum.
  • Un indirizzo per servizio: ogni servizio ha il proprio indirizzo onion, così non si possono collegare tra loro. L'SSH di amministrazione ne ha uno dedicato, diverso da quello del servizio pubblico.
  • La chiave è l'identità: hs_ed25519_secret_key non ha frase di recupero. Va salvata cifrata e fuori dal nodo, altrimenti perdere il disco significa perdere l'indirizzo.
  • Socket Unix al posto delle porte: con HiddenServicePort 80 unix:/var/run/web.sock il servizio non ascolta su alcuna porta di rete e non può essere raggiunto per errore dall'esterno.
  • Il server più piccolo possibile: Whonix suggerisce un server web di poche centinaia di righe per le pagine statiche e sconsiglia Apache per la sua complessità. Coincide con la scelta suckless del progetto.
  • Nessuna informazione gratuita: spegnere i banner di versione di ogni servizio e controllare che l'applicazione non riveli indirizzi interni, nomi host o pagine di stato.
  • Autorizzazione dei client: un servizio destinato a poche persone va protetto con l'autorizzazione dei client di Tor, che lo rende irraggiungibile, e perfino invisibile, a chi non possiede la chiave.
  • Provare prima di pubblicare: una scansione con OnionScan dall'esterno trova le configurazioni che tradiscono il server prima che lo faccia qualcun altro.
  • Disponibilità: la difesa proof-of-work e vanguards sono già descritte negli attacchi alla rete Tor; per i servizi più esposti si aggiungono OnionBalance e HiddenServiceExportCircuitID, che permette al proxy di limitare il traffico per circuito.
  • Gli orari parlano: un servizio che va giù insieme alla corrente di un quartiere, o a ogni manutenzione del suo operatore, rivela qualcosa. Vale quanto detto in Alimentazione.

Aggiornamenti, nome host e amministrazione

  • Aggiornare attraverso Tor: Whonix scarica i pacchetti da repository onion. Chi osserva la rete non deve poter sapere quale software è installato né a quale livello di correzione si trova. Su FreeBSD pkg rispetta la variabile SOCKS5_PROXY.
  • Un nome host anonimo: il nome della macchina trapela da DHCP, mDNS e dalla risoluzione inversa. Va scelto generico: un nodo che si annuncia al router come "Tutanum" ha già detto troppo. Lo stesso vale per i dispositivi portati fuori casa.
  • Amministrazione remota: ciò che si amministra da lontano va considerato osservabile da chi lo ospita. Anche su un canale cifrato, il ritmo di battitura e lo stile di scrittura restano un'impronta personale.

Il problema dei bridge

Molti dei bridge di Tor passano per uno dei 14 eyes, stati che praticano sorveglianza di massa. Sarà discusso anche il problema del parametro iat-mode=2.

Cosa sono

Sono server di rete privati, spesso di volontari, non pubblicizzati, utilizzati per connettersi alla rete tor, specialmente in aree dove l'accesso a internet o a tor è bloccato o limitato.
Vengono oltretutto impiegati per permettere una protezione a seguito di attacchi di correlazione, cioè attacchi in cui le intelligence deanonimizzano l'utente che si connette a tor, correlando l'entry node con l'exit node che loro rilasciano nella rete. Essendo di loro proprietà, il middle node fungerà da ponte permettendo la ricostruzione di tutto il circuito. Il bridge risolve questo problema poiché aggiunge prima dell'entry node un livello ulteriore.
Per superare la Deep Packet Inspection (DPI) dei firewall, i bridge utilizzano protocolli di offuscamento denominati pluggable transport.

Tipologie

Ciascun bridge è unico e può avere configurazioni diverse.
Ad oggi esistono 5 protocolli che si possono trovare per un bridge:

  • Obfs4: fa sembrare il traffico dati casuale.
  • Meek: fa credere di stare navigando su un comune sito web al posto di usare tor. Meek-azure fa credere di stare visitando un sito Microsoft.
  • Snowflake: instrada la connessione presso dei server proxy hostati da volontari, facendo credere di stare facendo una videochiamata al posto di stare usando tor.
  • ScrumbleSuit: permette di cambiare continuamente le caratteristiche del traffico (offuscamento polimorfico).

In sintesi, ciascun protocollo traveste il traffico in modo diverso (i dettagli sono nella sezione sui pluggable transport):

Client TorBridge obfs4CDN / CloudBridge MeekProxy WebRTCobfs4: byte casualiMeek: SNI lecitoSnowflake: WebRTC
I pluggable transport travestono il traffico del client per superare la DPI dei firewall.

Problemi

Non possiamo fidarci ciecamente di un bridge, non possiamo sapere chi lo possiede, per questo è necessario utilizzare i bridge configurati con un parametro chiamato iat-mode:

  • se è 0 significa senza offuscamento.
  • se è 1 significa che i dati vengono suddivisi in pacchetti di lunghezza stabilita a priori.
  • se è 2 significa che i dati vengono suddivisi in pacchetti di lunghezza variabile, solitamente casuale, rendendo più difficile l'analisi dei tempi e delle dimensioni del traffico in caso di intercettazione.

Esempio:

Bridge obfs4 37.136.134.70:3876 B7D366ECA3443481C1F4B774E50C2DBA6D7948CE cert=BeYU8A5nw3fTRxA8DphYvQrex3nV8StK3wG6/ZbFpmliJymdzAEafGdiD/zDw3wKIdJpLQ iat-mode=2

Parametro iat-mode=2

Alla fine vi è il parametro iat-mode=2.
Ad oggi è molto difficile trovare bridge con iat 1, figuriamoci 2.
Il sito ufficiale di Tor suggerisce che si possano reperire in 4 modi:

  • Tramite tor browser: è un browser insicuro, fornisce iat pari a 0 di default e che passano per i 14 eyes.
  • Tramite il sito: restituisce quasi praticamente sempre iat pari a 0 e che passano per i 14 eyes.
  • Tramite bot Telegram: restituisce sempre quei risultati, quasi sempre pari a 0 e che passano per i 14 eyes.
  • Tramite email: viene suggerito di inviare una richiesta via email usando Gmail, che è di Google o tramite Riseup, che è un servizio woke e socialista che probabilmente registrerà le richieste in arrivo, compromettendo pertanto a priori l'anonimato.

I bridge con iat-mode pari a 2 sono pochissimi perché questa modalità introduce ritardi artificiali aggressivi e pacchetti di padding vuoti, causando un degrado massiccio delle prestazioni (latenza, consumo di banda e di CPU) che satura le risorse dei server gestiti da volontari.
Il fatto che sia molto più probabile trovare bridge con iat-mode 0 o 1 implica che in paesi restrittivi come l'Iran si possano incrociare i dati dei firewall per rilevare l'utilizzo dei bridge, con il rischio di carcerazione per chi li usa.

Soluzioni

L'unica fonte sarebbe o cercare presso delle chat IRC qualcuno che dispone di bridge, esponendo tuttavia l'IP della propria rete e pertanto anche la propria posizione, oppure utilizzare i bridge che abbiamo ricavato da questo repository e che abbiamo ricavato dal post sulla configurazione del torrc (iat1, iat2). Evitare i bridge con IPv6 attivato in quanto potendo ricostruire il Mac Address del bridge implicherebbe verificarne le vulnerabilità, sfruttandole per poterne compromettere la sicurezza, innestandovi magari qualche spyware che possa portare alla conseguente compromissione dell'intero circuito di tor.

Conclusioni

I bridge sono essenziali nelle comunicazioni anonime su Tor, ma allo stato dell'ordine scarseggiano quelli con iat-mode pari a 2 e che non passano per i 14 eyes. Sarà che magari si dovranno studiare soluzioni alternative e che porteranno alla costruzione (1, 2, 3, 4, 5, 6) di bridge anonimi pure per l'IP. Per ora le alternative riguarderebbero l'utilizzo di tecnologie peer to peer, ma sarà ancora da vedere.

Pluggable transport: funzionamento e rilevamento

I protocolli di offuscamento usati dai bridge non sono invisibili: di seguito come funzionano i principali e in che modo vengono riconosciuti da chi ispeziona la rete.

obfs4 (offuscamento crittografico)

Trasforma il traffico in stringhe di byte totalmente casuali (entropia massima) per evitare la classificazione del protocollo e utilizza lo iat-mode (Inter-Arrival Time) per alterare la frequenza e la dimensione dei pacchetti, ostacolando l'analisi euristica dei firewall.
In pratica iat serve a mitigare il fingerprinting temporale del traffico, ossia l'analisi del pattern temporale dei pacchetti di rete per identificare o distinguere flussi di traffico specifici, correlando pertanto gli exit node con magari un entry node.
Toralf Förster sostiene che sia un errore dare in mano ai gestori dei bridge la possibilità di cambiare iat-mode, perché ritiene che il guadagno in termini di privacy sia dubbio e poco compreso: ciò che fanno i diversi tipi di iat è riorganizzare leggermente la temporizzazione tra i gruppi di byte inviati, nella speranza di confondere le firme di temporizzazione basate sul protocollo sottostante che obfs4 sta offuscando. A compromettere l'anonimato non è quindi tanto lo iat, quanto il rilevamento vero e proprio dei bridge con il relativo protocollo.

Il ricercatore Neal Krawetz sostiene in questo articolo che il Tor Project ostacoli le patch di sicurezza necessarie per un buon anonimato.
Un tempo ai provider bastava scaricare l'elenco dei nodi per bloccare tor, mentre ad oggi è sufficiente profilare il certificato TLS del server tor. La mitigazione del Tor Project è quella dei bridge, usati come dei proxy con protocollo PT (pluggable transport): il fatto che non siano in un elenco è ciò che consentirebbe loro di rimanere svincolati dalla censura.
Obfs4 rimane ad oggi il protocollo di offuscamento migliore, ma in Cina viene bloccato dal Great Firewall usando una scansione aggressiva e un'ispezione approfondita dei pacchetti (non è dato sapere altro). Da un punto di vista crittografico obfs4 è piuttosto solido, tuttavia gli sviluppatori sembrano essersi concentrati sulla crittografia e non sulla profilazione di rete, che consente di identificare l'intera famiglia obfs di pluggable transport (inclusi ScrambleSuit, obfs3 e obfs4) senza mai toccare la crittografia.

Rilevazione dei pacchetti obfs4

  1. Identificare l'intestazione dei pacchetti inviati ad una porta come la 22 o la 443: se non sono SSH, TLS o SSL allora si tratta di un protocollo trojan, perché non usa SSH o HTTPS. Se la porta è un'altra si procede comunque con il secondo punto, poiché potrebbe trattarsi di un bridge obfs4.
  2. Se l'ultimo pacchetto di dati che va dal client al server non usa il flag PSH (push, il bit che fa consegnare subito i dati all'applicazione ricevente), allora non è obfs4. Nel caso lo abbia si procede col prossimo punto.
  3. L'handshake di obfs4 e l'inizializzazione del tunnel di onion routing (OR) comportano il viaggio dei dati in una sola direzione alla volta (half duplex). Combinando questi 3 punti si può già escludere la maggior parte del traffico TCP.
  4. Quando il client obfs4 contatta per la prima volta il server obfs4, i due scambiano alcuni byte di dati. I primi due pacchetti scambiano parametri crittografici, quindi avviano il tunnel di onion routing. Il primo trasferimento va dal client al server (C→S), il secondo dal server al client (S→C). Tutto il resto non è obfs4.
  5. I dipendenti di Fortinet hanno elaborato le dimensioni dei pacchetti, incluso il padding casuale di dimensione variabile. Il primo C→S deve essere compreso tra 141 e 8192 byte ed è seguito dal primo S→C, tra 109 e 8160 byte.
  6. Dopo l'introduzione obfs4 inizia a trasmettere dati e tutti i trasferimenti devono essere compresi tra i 21 e gli 8192 byte. Basta controllare solo i primi 6 trasferimenti per questi intervalli di dimensioni per escludere la maggior parte del traffico non obfs4.
  7. Arrivati a questo punto il rilevamento risulta molto accurato, ma non al 100%: potrebbe perdere una connessione obfs4 su 10 (10% di falsi negativi) ed è possibile abbinare erroneamente altri protocolli.

Per eliminare i falsi positivi si incrociano più connessioni: se si rileva obfs4 su una connessione TCP, si controllano le connessioni simultanee verso altri server; ciascuna dovrebbe avere il primo trasferimento C→S con flag PSH e un payload che appare come byte casuali (nessun protocollo noto). Se il riscontro c'è, si tratta quasi certamente di obfs4. I falsi negativi, d'altra parte, non contano: basta intercettare una sola connessione obfs4 per stabilire che l'utente sta usando Tor con i bridge.

Meek (domain fronting)

Sfrutta le CDN dei grandi cloud provider. L'handshake TLS esterno (SNI) dichiara un dominio lecito e approvato (es. ajax.microsoft.com), ma una volta stabilita la sessione cifrata l'header HTTP Host interno, invisibile senza decifratura, reindirizza il traffico al bridge Tor reale.
In Cina ad oggi si usa meek al posto di obfs4 perché, essendo su un server Azure, per bloccarlo bisognerebbe bloccare anche Microsoft. Tuttavia è molto lento e la lentezza rende facile rilevare il bridge: basta tracciare i pacchetti TCP tra il client e il server meek (ajax.aspnetcdn.com) che hanno più di un kbyte nel payload. Sfruttando questo problema di timing si può discriminare il traffico di Microsoft da quello di tor.

Snowflake (WebRTC peer-to-peer)

Camuffa il traffico Tor trasformandolo in una normale sessione WebRTC (lo standard usato per le videochiamate di Teams, Zoom o Meet nel browser), instradando i dati attraverso il browser di un volontario che funge da proxy temporaneo.

Rilevamento dell'uso di Tor

Chi controlla una rete o un dispositivo può accorgersi dell'uso di Tor. Conoscere queste tecniche serve sia a capire quanto sia visibile il proprio traffico, sia a scoprire sulla propria infrastruttura una connessione Tor non autorizzata, che spesso indica tentativi di esfiltrazione di dati, violazioni delle policy o comunicazioni di malware e ransomware.

Telemetria di rete (firewall e proxy)

  • Verifica degli IP dei nodi pubblici: confrontare i log di rete in uscita con le liste degli exit node pubblici, utilizzando strumenti OSINT ufficiali come Tor Metrics (ExoneraTor) o Tor Relay Search.
  • Identificazione di obfs4 (alta entropia): ricercare sessioni TCP persistenti verso IP sconosciuti, classificate dal firewall come Unknown/Unclassified, che presentano un'entropia vicina al 100% (assenza totale di strutture dati note o di handshake TLS visibili).
  • Identificazione di Meek (SSL decryption): se sulla rete si effettua l'ispezione SSL, una regola può intercettare la discrepanza tra il dominio dichiarato nell'estensione SNI (es. microsoft.com) e l'header HTTP Host interno che punta a endpoint Tor.
  • Identificazione di Snowflake (STUN/TURN): monitorare l'avvio di connessioni WebRTC (pacchetti STUN) verso IP esterni che non corrispondono alle piattaforme di collaborazione autorizzate, precedute da query HTTPS verso i "broker" di Snowflake.

Endpoint Windows (Sysmon / EDR)

  • Sysmon Event ID 1 (Process Creation): monitorare la nascita di processi denominati tor.exe o obfs4proxy.exe. Verificare sempre l'hash SHA256, per escludere binari rinominati, e le esecuzioni da percorsi utente anomali (es. AppData\Local\Temp\).
  • Sysmon Event ID 3 (Network Connection): correlare direttamente i processi sopra identificati con le connessioni di rete generate verso l'esterno.
  • Sysmon Event ID 22 (DNS Query): tracciare le interrogazioni iniziali dell'applicazione verso i directory server di Tor, prima che la connessione entri nel tunnel cifrato.

Endpoint Linux (auditd / socket)

  • Auditd: monitorare i tentativi di esecuzione del binario tor e le modifiche al file di configurazione /etc/tor/torrc.
  • Verifica dei socket attivi: Tor apre localmente un proxy SOCKS, di default sulle porte 9050 o 9051. È possibile identificare un client Tor attivo verificando le porte in ascolto:
    ss -tulpn | grep -E "9050|9051"

Contenimento di una connessione non autorizzata

Se l'analisi conferma la presenza di una connessione alla rete Tor non autorizzata o malevola:

  1. Isolamento dell'host: isolare immediatamente la macchina dalla rete per bloccare qualsiasi flusso di esfiltrazione di dati o attività di Command & Control (C2).
  2. Reset delle credenziali: forzare il reset immediato delle credenziali dell'account utente associato a quell'endpoint.
  3. Bonifica: procedere alla formattazione completa e al ripristino dell'host compromesso, per eliminare alla radice la persistenza del client Tor o del malware che lo ha installato.
  4. Blocco degli IoC: inserire gli IP dei nodi identificati, i domini dei broker (es. Snowflake) o gli endpoint CDN abusati nella blacklist del firewall e del DNS.

Strumenti e risorse

Alcuni strumenti e riferimenti utili per lavorare con Tor, sul lato client e sul lato servizio:

  • Arti: reimplementazione in Rust del client Tor da parte del Tor Project, nata perché il codice originale in C è ormai difficile da mantenere (una sorta di "spaghetti code"). Punta a un'architettura più pulita, sicura e modulare (video introduttivo).
  • oniux: strumento a riga di comando del Tor Project che instrada attraverso Tor le connessioni di un singolo programma Linux isolandolo nei namespace del kernel, in modo più robusto rispetto a torsocks (che agisce solo sulle chiamate di libreria).
  • Tor with spoofing: risolve i domini via UDP anziché TCP per ridurre la latenza di Tor. Può essere utile dove la latenza conta, tenendo presente che l'UDP non garantisce la corretta ricezione dei dati.
  • Cover Your Tracks (EFF): verifica quanto il proprio browser sia identificabile tramite fingerprinting, utile per controllare che Tor Browser o un browser hardenizzato non emergano dalla massa.
  • Best practice per gli onion service (Riseup) e OWASP Cheat Sheet Series per la sicurezza applicativa del servizio che si espone.

Possibili attacchi alla rete tor

Alcuni articoli del ricercatore Neal Krawetz relativi alla compromissione di tor:

Gli attacchi descritti qui sotto sono tutti documentati nella letteratura pubblica (paper accademici, advisory del Tor Project e ricerca indipendente come quella di Neal Krawetz su hackerfactor). Sono riportati qui per capire da cosa un nodo Tutanum deve difendersi: per ciascuno c'è il meccanismo, uno schema o un PoC illustrativo e una nota di mitigazione. Gli esempi di codice servono a mostrare il principio (e a verificare la resistenza del proprio nodo) e operano su dati catturati sulla propria infrastruttura: non sono strumenti per deanonimizzare utenti o attaccare la rete Tor reale. Una tassonomia più ampia, con i relativi riferimenti, è nel repository Attacks on Tor e nella bibliografia sull'anonimato.

Modello di minaccia

Tor non protegge da un avversario globale che osservi contemporaneamente tutti i collegamenti della rete: il suo modello assume un avversario parziale, che controlla o osserva solo una frazione dei nodi e dei link. Quasi tutti gli attacchi puntano quindi a far sì che l'avversario si trovi su entrambi gli estremi del circuito (ingresso e uscita), oppure a ricondurre un flusso cifrato ad un'identità tramite caratteristiche collaterali. Le posizioni tipiche dell'avversario:

UtenteGuardMiddleExitSitoosserva l'ingressoosserva l'uscitagestisce il guardcorrelazione all'uscita
Le deanonimizzazioni nascono quando lo stesso avversario vede o controlla entrambi gli estremi del circuito.

La grande maggioranza delle deanonimizzazioni reali nasce dalla combinazione controllo del guard + correlazione all'uscita, eventualmente agevolata dagli attacchi di supporto (per aumentare la frazione di rete controllata) e di disponibilità (per spingere la vittima sui nodi dell'avversario).

Attacchi di rivelazione degli hidden service

Mirano a scoprire l'IP reale del server che ospita un servizio .onion, che per definizione dovrebbe restare nascosto.

Attacco del primo nodo

Se l'avversario riesce a diventare il guard (il primo nodo) dell'hidden service e a identificarlo come tale, vede l'IP reale del server. Nelle vecchie versioni del protocollo (hidden service v2) un avversario che gestiva molti relay poteva, aprendo ripetutamente circuiti verso il servizio, aumentare la probabilità di essere scelto come guard e distinguere la propria posizione; combinando questo con un attacco di congestione o di clock skew (sotto) confermava quale server stesse ospitando il servizio.

[Avversario-guard] ◄── circuito ──► [Hidden Service] │ ▲ └─ vede l'IP reale ─────────────────┘ e lo conferma con congestione/clock skew

Mitigazione: L'obiettivo è non trovarsi mai con l'avversario in posizione di guard e impedirgli di forzare la scoperta del guard tramite DoS/ricostruzioni:

  • Installare l'addon vanguards, che aggiunge strati di guard di secondo e terzo livello: è la difesa principale per un onion service.
  • Usare onion service v3 e non azzerare i guard (non cancellare il file state).
  • Attivare la difesa anti-DoS proof-of-work, che toglie all'avversario il modo economico di forzare nuovi circuiti verso il servizio per isolarne il guard.
# torrc del servizio onion HiddenServiceVersion 3 HiddenServicePoWDefensesEnabled 1 # Tor >= 0.4.8: ostacola il forced-circuit per scovare il guard UseEntryGuards 1 NumEntryGuards 1 # un solo guard stabile di lungo periodo # Tor >= 0.4.8 include vanguards-lite. L'addon vanguards completo (layer-2/3 guard) parla con Tor # dal socket di controllo, protetto dal cookie: ControlSocket /var/run/tor/control CookieAuthentication 1 # vanguards --control_socket /var/run/tor/control

PoC di verifica: Controllare dalla porta di controllo che i guard siano pochi e stabili nel tempo (ripetendo il comando a distanza di giorni non devono cambiare):

doas jexec tor sh -c 'printf "AUTHENTICATE %s\r\nGETINFO entry-guards\r\nQUIT\r\n" \ "$(hexdump -ve "1/1 \"%02x\"" /var/db/tor/control_auth_cookie)" | nc -U /var/run/tor/control'

Una porta di controllo TCP senza autenticazione permetterebbe a qualunque processo che la raggiunge di comandare Tor: si usa il socket locale con il cookie.

Attacco di disallineamento dell'orologio

Descritto da Steven Murdoch in Hot or Not: Revealing Hidden Services by their Clock Skew. Il clock skew è la piccola deriva costante dell'orologio di una macchina rispetto al tempo reale. La frequenza del quarzo che genera il clock dipende dalla temperatura: aumentando il carico della CPU di un server (inviandogli molte richieste) se ne alza la temperatura e se ne modifica in modo misurabile lo skew. L'avversario invia quindi traffico ad un hidden service sospetto e, in parallelo, misura lo skew di un server candidato leggendo i TCP timestamp: se lo skew del candidato varia in sincronia con il carico indotto, il candidato è il server dell'hidden service.

Lo skew si stima dalla pendenza dell'errore dei timestamp rispetto al tempo di arrivo. Su una cattura fatta sul proprio server se ne può osservare l'andamento per verificare quanto sia esposto:

import numpy as np # t_rx = istante di arrivo del pacchetto (orologio dell'osservatore, in secondi) # ts = valore del campo TCP Timestamp del server (in "tick") # hz = frequenza del contatore TSval del server (tipicamente 100, 250 o 1000) offset = (ts / hz) - t_rx # errore dell'orologio del server nel tempo skew_ppm = np.polyfit(t_rx, offset, 1)[0] * 1e6 # pendenza -> skew in parti per milione # una variazione dello skew correlata al carico indotto "tradisce" il server

Mitigazione: Togliere il canale (i TCP timestamp), stabilizzare l'ambiente e non esporre il server a carichi arbitrari:

  • Disabilitare i TCP timestamp a livello di kernel.
  • Mantenere stabile la temperatura del locale e regolare l'orologio senza NTP in chiaro, che esporrebbe proprio l'ora del nodo (vedi Il tempo come vettore d'attacco).
  • Esporre il server solo come onion service, così che nessun estraneo possa indurgli carico diretto.
# FreeBSD / OpenBSD (/etc/sysctl.conf) net.inet.tcp.rfc1323=0 # disattiva timestamp (e window scaling) # Linux (/etc/sysctl.d/99-tutanum.conf) net.ipv4.tcp_timestamps=0 # applicare: sysctl -f /etc/sysctl.conf (BSD) | sysctl --system (Linux)

PoC di verifica: Confermare che l'opzione sia spenta e che sul filo non compaiano i timestamp:

sysctl net.inet.tcp.rfc1323 # BSD -> 0 sysctl net.ipv4.tcp_timestamps # Linux -> 0 doas tcpdump -n -v 'tcp[tcpflags] & tcp-syn != 0' | grep -i tsval # non deve stampare nulla

Attacchi di deanonimizzazione

Mirano a ricondurre l'attività di un utente (il lato client) alla sua identità o al suo IP reale.

Attacco sul fingerprint

Il website fingerprinting è un attacco passivo e locale: un osservatore posizionato tra l'utente e il guard (l'ISP, l'amministratore della rete, o il guard stesso) non vede il contenuto cifrato, ma vede la forma del traffico, sequenza di dimensioni dei pacchetti, direzione e tempi. Queste caratteristiche sono abbastanza stabili da permettere a un classificatore (oggi reti neurali) di indovinare quale sito l'utente stia visitando, scelto tra un insieme noto. Un PoC pubblico e didattico è website-fingerprinting.

Il principio della fase di estrazione delle feature da una traccia (dimensioni con segno per la direzione: positivo = ricevuto, negativo = inviato):

def features(traccia): # traccia: lista di (timestamp, lunghezza_con_segno) direzioni = [1 if l > 0 else -1 for _, l in traccia] cumulativo = [] # dimensione cumulata: "forma" della pagina s = 0 for _, l in traccia: s += l cumulativo.append(s) return { "n_pacchetti": len(traccia), "byte_in": sum(l for _, l in traccia if l > 0), "byte_out": -sum(l for _, l in traccia if l < 0), "burst_out": max_run(direzioni, -1), # raffica più lunga in uscita "cumulativo": cumulativo, # dato in pasto al classificatore }

Mitigazione: Il fingerprinting sfrutta la forma del traffico, non la cifratura: si uniforma il comportamento e si aggiunge padding.

  • Mantenere attivo il circuit padding (WTF-PAD, già di default) e il connection padding.
  • Usare Tor Browser, che rende tutti gli utenti simili tra loro, e preferire gli onion service, dove l'attacco è più debole.
  • Lato client, non usare client Tor personalizzati che alterano i pattern in modo riconoscibile.
# torrc ConnectionPadding 1 ReducedConnectionPadding 0 # NON ridurre il padding CircuitPadding 1 # padding di circuito (default)

PoC di verifica: Controllare quanto il proprio browser sia distinguibile con Cover Your Tracks; un Tor Browser standard risulta "non unico". Dalla porta di controllo si può verificare che il padding sia negoziato sui circuiti con GETINFO circuit-status.

Attacco sul relay anticipato

È l'attacco di traffic confirmation reso pubblico dal Tor Project nel security advisory del luglio 2014. Un gruppo di relay malevoli, trovandosi sia come guard/HSDir del lato client sia come nodo del lato servizio, codificava un segnale modulando la sequenza di celle di tipo relay e relay_early: il nodo d'ingresso "scriveva" nel pattern delle celle un identificativo che il nodo complice leggeva dall'altra parte, realizzando una conferma end-to-end senza bisogno di analisi statistica.

[Guard complice] ─ pattern relay/relay_early = "firma" ─► ... ─► [Nodo complice] inietta la firma riconosce la firma └──────────────── stesso avversario: correlazione confermata ───────────────┘

Mitigazione: La variante specifica è stata corretta: le celle relay_early non possono più essere usate così e ne è limitato il conteggio. La difesa operativa è mantenere il software aggiornato e usare guard stabili.

doas pkg upgrade tor # FreeBSD tor --version # dev'essere recente: la falla è del 2014

PoC di verifica: Confrontare la versione installata con l'ultima release stabile del Tor Project e tenere attivo l'aggiornamento automatico dei pacchetti di sicurezza.

Attacco RAPTOR

Descritto in RAPTOR: Routing Attacks on Privacy in Tor. Sposta la correlazione al livello degli Autonomous System (gli operatori di rete che instradano il traffico BGP). Un AS che vede il traffico tra utente e guard e quello tra exit e destinazione può correlarli; RAPTOR aggiunge tre leve: la correlazione asimmetrica (basta vedere una direzione in ciascun punto), lo sfruttamento della naturale instabilità delle rotte BGP, e soprattutto il dirottamento o l'intercettazione BGP per mettersi attivamente sul percorso.

Mitigazione: Spezzare la possibilità che un unico AS veda entrambi i capi:

  • Distribuire i propri nodi su provider e sistemi autonomi diversi; evitare di concentrarli sotto lo stesso operatore.
  • Preferire gli onion service: senza exit node non c'è traffico in chiaro verso una destinazione su un AS osservabile.
  • Mantenere la diversità di sottorete. Escludere interi paesi riduce troppo la rete (vedi Torrc consigliato): al massimo si esclude il proprio per il guard.
  • Per il proprio prefisso IP: pubblicare una ROA RPKI e monitorare gli annunci BGP (es. BGPalerter) per accorgersi di dirottamenti.
# torrc EnforceDistinctSubnets 1
Attacco di congestione

Introdotto da Murdoch e Danezis in Low-Cost Traffic Analysis of Tor. Con un solo relay e un client, l'avversario misura la latenza di tutti i relay candidati (mandando richieste di prova) mentre invia raffiche di traffico attraverso il circuito della vittima: i relay che fanno parte di quel circuito mostrano un aumento di latenza sincrono con le raffiche, rivelando così i nodi del circuito.

Mitigazione: Non lasciare che la congestione indotta produca un segnale misurabile né esaurisca le risorse:

  • Tenere i nodi con banda abbondante e non saturi.
  • Limitare la memoria delle code e usare lo scheduler KIST (default), che riduce l'accodamento.
# torrc MaxMemInQueues 512 MB Schedulers KIST,KISTLite,Vanilla RelayBandwidthRate 10 MB RelayBandwidthBurst 20 MB
Attacco di riduzione indiretta del rate

Variante attiva della congestione: invece di misurare, l'avversario strozza selettivamente alcuni relay (induced throttling) per forzare la ricostruzione dei circuiti o per imprimere nel flusso un calo di velocità riconoscibile all'altro estremo. Spingendo la vittima a cambiare percorso ne aumenta anche la probabilità che prima o poi scelga un nodo dell'avversario.

Mitigazione: Meno ricostruzioni di circuito significano meno occasioni per l'avversario: guard persistenti, margine di banda e limiti di memoria, più monitoraggio della banda per accorgersi di strozzature anomale.

# torrc UseEntryGuards 1 MaxMemInQueues 512 MB RelayBandwidthRate 10 MB RelayBandwidthBurst 20 MB

PoC di verifica: Monitorare nel tempo la banda effettiva del proprio relay (es. con vnstat o le metriche di nyx) e indagare i cali improvvisi e selettivi.

Attacco di stima della larghezza di banda

La probabilità che un relay sia scelto è proporzionale alla banda che dichiara. Un avversario può gonfiare la banda dichiarata (bandwidth inflation) per attrarre più traffico e aumentare la frazione di circuiti in cui compare, agevolando tutti gli attacchi di correlazione. È più una leva di supporto che un attacco a sé.

Mitigazione: La rete non si fida più della banda auto-dichiarata ma la misura con le bandwidth authority (sbws). Dal lato operatore la difesa è non contribuire all'attacco: dichiarare valori realistici, mai gonfiati.

# torrc RelayBandwidthRate 8 MB RelayBandwidthBurst 16 MB # valori coerenti con la banda reale: le incongruenze con la misura sbws vengono penalizzate
Attacco della mela marcia

Da One Bad Apple Spoils the Bunch. Sfrutta un'applicazione insicura usata sopra Tor, tipicamente un client BitTorrent che annuncia il proprio IP reale nel payload, per deanonimizzare l'utente. E poiché più flussi dello stesso utente possono condividere lo stesso circuito, la "mela marcia" contamina anche le altre sessioni (es. la navigazione) che passano per quel circuito.

Mitigazione: Non far condividere lo stesso circuito a flussi di natura diversa e non far passare mai sopra Tor applicazioni che rivelano l'IP:

  • Non usare P2P/BitTorrent sopra Tor.
  • Sfruttare la stream isolation e, meglio ancora, porte SOCKS separate per applicazioni diverse.
# torrc SocksPort 9050 IsolateSOCKSAuth IsolateClientAddr IsolateDestAddr IsolateDestPort SocksPort 9052 IsolateClientAddr # porta dedicata a un'altra applicazione

PoC di verifica: Da due applicazioni/porte diverse l'IP di uscita deve risultare diverso (circuiti isolati):

curl --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/api/ip curl --socks5-hostname 127.0.0.1:9052 https://check.torproject.org/api/ip
Attacco probabilistico

Non è un singolo exploit ma il limite statistico di fondo: un avversario che controlla una frazione c dei relay (pesati per banda) ha, su un circuito costruito a caso, probabilità circa c² di controllarne sia l'ingresso sia l'uscita. Ripetendo su molti circuiti nel tempo questa probabilità di essere "visti" almeno una volta tende a crescere.

1 circuito: P(entrambi gli estremi) ≈ c² n circuiti (ingenuo): P(almeno una volta) ≈ 1 − (1 − c²)ⁿ ──► cresce con n

Mitigazione: È esattamente il motivo per cui esistono gli entry guard: fissando pochi guard di lungo periodo, l'utente non "rigioca" il lato ingresso ad ogni circuito e la probabilità non cresce più con il numero di circuiti.

# torrc UseEntryGuards 1 NumEntryGuards 1 # (default) un solo guard di lungo periodo GuardLifetime 0 # 0 = usa il default (mesi); non accorciare la durata # non cancellare il file "state": contiene i guard selezionati

PoC di verifica: Il guard elencato da GETINFO entry-guards deve restare lo stesso per settimane; un cambio frequente indica rotazione indesiderata (state resettato, riavvii che perdono lo stato).

Attacchi di correlazione

Sono il cuore della deanonimizzazione: avendo visibilità su ingresso e uscita, l'avversario dimostra che due flussi cifrati sono lo stesso flusso. Non rompono la cifratura, confrontano tempi e volumi. Lo schema statistico comune confronta le serie dei byte-per-intervallo ai due estremi:

import numpy as np # in_series, out_series: byte conteggiati per finestra di tempo (es. 100 ms) # catturati ai due capi di circuiti della PROPRIA rete di test def correla(in_series, out_series): a = np.asarray(in_series, float) b = np.asarray(out_series, float) a -= a.mean(); b -= b.mean() return float((a @ b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-9)) # valori vicini a 1 = i due flussi sono quasi certamente lo stesso # tecniche moderne (es. DeepCorr) usano reti neurali al posto della correlazione lineare

I paragrafi seguenti sono varianti di come si crea o si rende robusto quel segnale. Riferimento moderno: DeepCorr.

Attacco di ripetizione

L'avversario che controlla l'ingresso duplica (rigioca) una cella del flusso. Per come è strutturata la cifratura a contatore di Tor, la cella duplicata altera lo stato crittografico a valle e provoca un errore di integrità riconoscibile proprio al nodo di uscita: se è lui stesso, ha la conferma. È una firma attiva anziché statistica.

Mitigazione: Tor rileva e scarta le celle duplicate grazie al controllo di integrità del protocollo: è una difesa nativa. L'unica azione operativa è mantenere il software aggiornato.

tor --version # verificare che sia una versione supportata e aggiornata
Attacco basato sul conteggio delle celle

Invece di duplicare, l'avversario all'ingresso modula il numero di celle inviate in ogni raffica per codificare un identificativo (per esempio raffiche di 3-1-3-2 celle); l'avversario all'uscita conta le celle e ricostruisce lo stesso pattern. È una forma di marcatura a basso costo e difficile da notare per la vittima.

ingresso: ███ █ ███ ██ (3,1,3,2 celle = simbolo) uscita: ███ █ ███ ██ stesso conteggio -> stesso flusso

Mitigazione: Il padding di circuito e l'aggregazione delle celle rendono il conteggio delle raffiche meno affidabile; vanno mantenuti attivi.

# torrc ConnectionPadding 1 ReducedConnectionPadding 0 CircuitPadding 1
Attacco di analisi del traffico basato sulla correlazione

È la versione passiva e generale: senza iniettare nulla, l'avversario confronta le serie temporali di byte/pacchetti ai due estremi (con la correlazione mostrata sopra o con modelli di deep learning) e, se combaciano, collega utente e destinazione. È l'attacco più realistico contro un avversario che vede entrambi i capi, ed è il motivo per cui Tor non promette anonimato contro un osservatore end-to-end.

Mitigazione: Contro un avversario che vede entrambi i capi non esiste una difesa assoluta; si lavora per renderlo improbabile e per sporcare il segnale:

  • Diversità di percorso (nodi su AS e paesi diversi) e guard stabili.
  • Onion service, così che entrambi i capi restino dentro la rete e non ci sia un punto di osservazione in chiaro.
  • Padding di circuito attivo per attenuare la correlazione temporale.
# torrc ConnectionPadding 1 EnforceDistinctSubnets 1 UseEntryGuards 1
Attacco di routing a basse risorse

Da Bauer et al., Low-Resource Routing Attacks Against Tor. Con pochi mezzi, dei relay malevoli dichiarano banda e uptime elevati (mentendo) per essere scelti spesso come ingresso e uscita; una volta in posizione su entrambi i capi di abbastanza circuiti, applicano la correlazione. Combina la stima della banda con la probabilità.

Mitigazione: La misura indipendente della banda (sbws) e gli entry guard tolgono gran parte dell'efficacia a questa classe di attacchi, è la ragione storica per cui i guard sono stati introdotti. Dal lato operatore: mantenere il software aggiornato e i guard stabili.

# torrc UseEntryGuards 1 NumEntryGuards 1
Attacco di iniezione di pattern HTTP

Attacco a livello applicativo: un exit malevolo (o il sito stesso) inietta nel contenuto una firma riconoscibile, oggetti di dimensioni precise, richieste temporizzate, un beacon JavaScript, in modo da creare all'ingresso un pattern di traffico inconfondibile e facilitare la correlazione, o da far rivelare al browser informazioni identificative.

Mitigazione: Togliere all'exit (o al sito) la possibilità di iniettare o alterare contenuto e di far "parlare" il browser:

  • HTTPS end-to-end con HSTS: un exit non vede né altera il contenuto cifrato.
  • Onion service: non c'è alcun exit.
  • Tor Browser con NoScript e JavaScript disattivato sui siti non fidati.
  • Lato servizio, impostare HSTS e una Content-Security-Policy restrittiva.
# nginx del servizio esposto add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always; add_header Content-Security-Policy "default-src 'self'" always; add_header X-Content-Type-Options "nosniff" always;
Attacco di watermarking del tempo dei pacchetti

Versione attiva e robusta della correlazione temporale: l'avversario all'ingresso incorpora un watermark ritardando leggermente certi pacchetti secondo uno schema segreto (tecniche tipo RAINBOW o SWIRL). Il watermark è progettato per sopravvivere a jitter e ritardi e viene riconosciuto all'uscita, dando una conferma molto affidabile anche su pochi pacchetti.

pacchetti: │ │ │ │ │ │ ──► ritardi mirati ──► │ ││ │ ││ originale (watermark) schema riconoscibile all'uscita

Mitigazione: Introdurre ritardi/padding casuali spezza il watermark: è l'ennesimo motivo per tenere attivo il circuit padding ed evitare circuiti troppo longevi che facilitano la marcatura.

# torrc ConnectionPadding 1 ReducedConnectionPadding 0 CircuitPadding 1 MaxCircuitDirtiness 600 # ricambio ragionevole dei circuiti (default 10 min)

Attacchi di supporto e disponibilità

Non deanonimizzano da soli, ma abilitano gli altri aumentando la quota di rete controllata dall'avversario o spingendo la vittima verso i suoi nodi.

Attacco di supporto

Comprende le tecniche ausiliarie che preparano il terreno: l'attacco Sybil (immettere nella rete un gran numero di relay controllati, per aumentare c), l'enumerazione dei bridge (scoprire i bridge non pubblici per bloccarli o sorvegliarli) e in generale la gestione del piano di gestione dei relay. Da soli non rivelano nulla, ma portano l'avversario nelle condizioni del modello di minaccia (entrambi gli estremi).

Mitigazione: Alzare il costo per l'avversario di aumentare la propria quota di rete:

  • Entry guard e banda misurata (sbws) limitano l'utilità di immettere molti relay.
  • Se si gestiscono più relay propri, dichiararli come famiglia così da non finire mai nello stesso circuito, e distribuirli su identità/AS distinti per non contribuire a una Sybil.
  • Usare bridge con pluggable transport per non esporsi all'enumerazione dei bridge pubblici.
# torrc (operatore di più relay) MyFamily <fingerprint-relay-1>,<fingerprint-relay-2> # client dietro censura: UseBridges 1 ClientTransportPlugin obfs4 exec /usr/bin/obfs4proxy managed
Attacco DoS

La negazione del servizio ha due scopi: rendere Tor inutilizzabile, oppure, più subdolamente , abbattere i relay onesti per costringere la vittima a ricostruire i circuiti finché non sceglie un nodo dell'avversario (congiunzione con l'attacco del primo nodo). L'esempio canonico è lo Sniper Attack: un client malevolo dichiara una finestra di ricezione ampia e poi smette di leggere, facendo accumulare dati in coda al relay bersaglio fino all'esaurimento della memoria (OOM) e al suo crash, a costo quasi nullo per l'attaccante. Sullo stesso filone, Krawetz descrive come mandare in crash la rete Tor.

[Client sniper] ─ "finestra enorme, ma non leggo mai" ─► [Relay bersaglio] coda in RAM ↑↑↑ ─► OOM / crash

Mitigazione: Chiudere il vettore di esaurimento memoria dello Sniper Attack e limitare le risorse, a livello sia di Tor sia di sistema operativo:

  • Limitare la memoria delle code di Tor (MaxMemInQueues): è la contromisura diretta all'OOM indotto.
  • Attivare la difesa proof-of-work sugli onion service per rendere costoso il flooding.
  • Imporre limiti di memoria e di descrittori al processo tor dal sistema operativo.
  • Rate limiting e monitoraggio delle code (già trattati in firewall e monitoraggio).
# torrc MaxMemInQueues 512 MB HiddenServicePoWDefensesEnabled 1 # FreeBSD /etc/login.conf (classe dell'utente _tor): limite di memoria # tor:\ # :memoryuse=1G:\ # :openfiles=8192:\ # :tc=default: # poi: cap_mkdb /etc/login.conf # Linux (systemd override del servizio tor): # [Service] # MemoryMax=1G # LimitNOFILE=8192

PoC di verifica: Controllare che le mitigazioni siano effettivamente attive:

grep -E 'MaxMemInQueues|PoWDefenses' /usr/local/etc/tor/torrc doas jexec tor sh -c 'printf "AUTHENTICATE %s\r\nGETINFO onions/current\r\nQUIT\r\n" \ "$(hexdump -ve "1/1 \"%02x\"" /var/db/tor/control_auth_cookie)" | nc -U /var/run/tor/control'

Un servizio esposto solo come onion elimina inoltre l'IP pubblico come bersaglio: non essendo raggiungibile direttamente, il DoS volumetrico classico non lo colpisce e l'attaccante deve passare per la rete Tor, motivo per cui gli hidden service sono considerati relativamente resistenti al DoS (tesi UniCam). Non sono però immuni: la rete Tor ha conosciuto vere e proprie ondate di DoS. Per i DDoS a livello applicativo su un nodo Tutanum resta utile fail2ban, mentre la ridondanza dei servizi onion si ottiene con OnionBalance.

I2P

I2P (Invisible Internet Project) è una rete anonima overlay, a commutazione di pacchetto e completamente distribuita: non esistono directory authority centrali (Tor ne ha circa dieci) e ogni nodo è contemporaneamente client e router per gli altri. È ottimizzata per i servizi nascosti interni alla rete (gli eepsite, cioè i siti .i2p) più che per l'accesso al web in chiaro: la maggior parte del traffico resta dentro I2P. Proprio la totale decentralizzazione, unita a trasporti offuscati per impostazione predefinita, la rende oggi una delle reti più solide sul fronte dell'anticensura. Per questo è la rete scelta ufficialmente per i servizi di Tutanum: il sito è pubblicato come eepsite, mentre Tor resta impiegato per l'uscita verso il web in chiaro.

Cos'è I2P e differenze con Tor

I due progetti condividono l'idea di instradare il traffico cifrato attraverso più nodi volontari, ma partono da scelte architetturali diverse:

  • Nessuna autorità centrale. In Tor un piccolo gruppo di directory authority firma il consenso sulla rete; sono un punto noto da attaccare o bloccare. In I2P le informazioni di rete vivono in un database distribuito (la NetDB), senza un punto di strozzatura unico.
  • Tunnel unidirezionali al posto dei circuiti bidirezionali: ogni nodo mantiene tunnel di uscita e tunnel di ingresso separati.
  • Garlic routing al posto del semplice onion routing: più messaggi vengono raggruppati e cifrati insieme.
  • Orientata all'interno. Tor nasce per uscire verso il web in chiaro tramite gli exit node; I2P nasce come "rete nella rete", dove i servizi sono raggiungibili solo da dentro I2P. Esistono degli outproxy verso il clear web, ma sono pochi e sconsigliati.
  • Ogni partecipante instrada. Un router I2P, per impostazione predefinita, fa transitare anche il traffico altrui: l'anonimato di base è "tutti sono relay", mentre in Tor il client non è un relay.

Architettura della rete

Ogni nodo è un router identificato da una RouterIdentity (le sue chiavi pubbliche) e comunica con gli altri costruendo dei tunnel. Un punto raggiungibile (un eepsite, un servizio) è una Destination, anch'essa un'identità crittografica.

Tunnel unidirezionali

A differenza dei circuiti bidirezionali di Tor, in I2P i tunnel sono a senso unico: ogni router ne costruisce di outbound (per inviare) e di inbound (per ricevere). Uno scambio completo richiede quindi quattro tunnel: il mio outbound e l'inbound del destinatario per l'andata, il suo outbound e il mio inbound per il ritorno. Ciò limita quanto un singolo nodo di passaggio può dedurre, al costo di raddoppiare i tunnel.

Atunnel OUTBOUND di Atunnel INBOUND di BBmessaggioBtunnel OUTBOUND di Btunnel INBOUND di AArisposta
I tunnel I2P sono unidirezionali: uno scambio completo richiede quattro tunnel (i puntini sono i salti).

Ogni tunnel è formato da un gateway (ingresso), zero o più partecipanti intermedi e un endpoint (uscita). Vive circa 10 minuti e poi viene ricostruito; i router li gestiscono in pool e ne variano la lunghezza (tipicamente 3 hop, ma con una varianza casuale) per ostacolare la profilazione.

Garlic routing

Il garlic routing estende l'onion routing: invece di un singolo messaggio sbucciato strato per strato, un garlic message impacchetta più clove ("spicchi"), ciascuna con le proprie istruzioni di consegna, il tutto cifrato end-to-end. Raggruppare più messaggi (dati, il proprio LeaseSet per farsi rispondere, conferme) in un unico pacchetto rende più difficile l'analisi del traffico.

Garlic message, cifrato end-to-endclove 1 → dati applicativi per Bclove 2 → LeaseSet di A (per la risposta)clove 3 → conferma / copertura
Il garlic routing impacchetta più messaggi (clove) in un unico invio cifrato end-to-end.

Il database di rete (NetDB)

La NetDB è una tabella hash distribuita, variante di Kademlia, che conserva due tipi di record:

  • RouterInfo: descrive un router (identità, indirizzi, trasporti supportati, capacità).
  • LeaseSet: descrive una Destination, elencando i lease, cioè i gateway dei suoi tunnel inbound correnti, con la relativa scadenza.

A conservare e servire la NetDB sono i router floodfill (quelli con banda e uptime adeguati). Per resistere agli attacchi mirati, la chiave di routing di un record ruota ogni giorno: è calcolata come SHA256(hash_destinazione || data_odierna), così i floodfill responsabili di una certa destinazione cambiano quotidianamente. Il bootstrap iniziale (ottenere i primi RouterInfo) avviene tramite reseed da un piccolo insieme di server HTTPS con bundle firmati.

Destinazioni e LeaseSet

Una Destination è l'identità crittografica di un endpoint (come un indirizzo .onion in Tor). Il suo indirizzo è la base32 dell'hash delle chiavi, nella forma <52 caratteri>.b32.i2p, e può ricevere un nome leggibile .i2p tramite l'addressbook e i jump service. Per contattare B, il router di A cerca nella NetDB il LeaseSet di B, ne ricava i gateway dei tunnel inbound e vi instrada il garlic message attraverso un proprio tunnel outbound.

Router AFloodfillDest. B1. richiesta LeaseSet di B2. LeaseSet = gateway inbound di B3. invio via tunnel ai gateway inbound di B
Per raggiungere B, A ricava dal floodfill il LeaseSet di B (i gateway dei suoi tunnel inbound).

Crittografia e trasporti

I2P cifra su più livelli indipendenti: la cifratura end-to-end (garlic) tra le due Destination, la cifratura di tunnel (AES-256) salto per salto lungo ciascun tunnel, e la cifratura di trasporto tra router adiacenti.

Trasporti: NTCP2 e SSU2

I collegamenti tra router usano due trasporti, entrambi basati sul framework Noise e progettati per apparire come byte casuali, quindi resistenti alla DPI senza bisogno di pluggable transport esterni:

  • NTCP2 (su TCP): handshake Noise con chiavi effimere e cifrario ChaCha20-Poly1305; ha sostituito il vecchio NTCP in chiaro.
  • SSU2 (su UDP): oltre alla cifratura offre l'attraversamento dei NAT e il peer testing; ha sostituito il vecchio SSU.

È una differenza importante rispetto a Tor: in I2P l'offuscamento del traffico di trasporto è nativo e predefinito, mentre Tor "in chiaro" è riconoscibile dal certificato TLS e necessita di bridge con obfs4 per mimetizzarsi.

Cifratura end-to-end: ECIES-X25519 ratchet

Lo schema storico (ElGamal a 2048 bit + AES-256-CBC con SessionTag) è deprecato. Oggi il predefinito è ECIES-X25519-AEAD-Ratchet: scambio di chiavi su curva X25519, cifrario ChaCha20-Poly1305 e un meccanismo a ratchet (simile al double ratchet di Signal) che fornisce forward secrecy rinnovando continuamente le chiavi di sessione.

Anticensura e resistenza al blocco

La robustezza di I2P contro la censura nasce da tre fattori:

  • Nessuna directory authority. Non esiste un elenco centrale da bloccare o da mandare in DoS: per isolare la rete un censore dovrebbe enumerare e bloccare un gran numero di peer distribuiti.
  • Trasporti offuscati di default. NTCP2 e SSU2 appaiono come traffico casuale, quindi la DPI non li distingue facilmente, senza dover ricorrere a ponti dedicati.
  • Instradamento interno. Non dipendendo da exit node verso il clear web, I2P non espone il punto debole della lista pubblica degli exit.

Il punto più fragile resta il reseed: per entrare in rete la prima volta un nuovo router scarica i RouterInfo iniziali da pochi server HTTPS, che un censore può bloccare. Le mitigazioni sono il reseed da più server, via Tor o proxy, oppure da un file di bundle firmato (SU3) ottenuto per altri canali. Va detto anche che la rete I2P è più piccola di Tor: l'insieme di anonimato è inferiore, ma l'infrastruttura è più difficile da censurare nel suo complesso (cfr. gli studi sulla resistenza alla censura di I2P).

Configurare un nodo I2P

Esistono due implementazioni principali: il router di riferimento in Java (geti2p) e i2pd, scritto in C++, molto più leggero e adatto a hardware modesto o a *BSD, quindi la scelta naturale per un nodo Tutanum. Un vantaggio pratico rispetto ad Hyphanet: I2P ospita senza problemi siti dinamici, perché l'eepsite è semplicemente un normale web server locale esposto tramite un tunnel.

Impostazioni di base del router (~/.i2pd/i2pd.conf):

# ~/.i2pd/i2pd.conf ipv4 = true ipv6 = false bandwidth = L # L = 32 KB/s ... X = illimitato; più banda = più utile alla rete port = 23456 # porta dei trasporti NTCP2/SSU2 (scegliere a caso e aprire sul firewall) floodfill = false # diventare floodfill solo con banda e uptime elevati e stabili [ntcp2] enabled = true [ssu2] enabled = true [limits] transittunnels = 2500 # quanto traffico altrui si è disposti a far transitare

Per pubblicare il sito dinamico di Tutanum come eepsite si definisce un server tunnel (~/.i2pd/tunnels.conf) che punta al web server locale:

# ~/.i2pd/tunnels.conf [tutanum-web] type = http # tunnel server HTTP (eepsite) host = 127.0.0.1 port = 8080 # il web server locale di Tutanum keys = tutanum.dat # chiave della Destination: da qui deriva l'indirizzo .b32.i2p inbound.length = 3 # lunghezza dei tunnel (più alta = più anonimato, più latenza) outbound.length = 3 inbound.quantity = 3 # tunnel ridondanti per disponibilità outbound.quantity = 3

Al primo avvio i2pd genera tutanum.dat e il relativo indirizzo .b32.i2p, da comunicare agli utenti. Per i consigli di sicurezza nell'esporre un servizio valgono gli stessi principi di hardening visti per gli onion service.

Raggiungibilità: router firewallato, CGNAT, senza controllo del router

Un nodo che offre un servizio deve poter ricevere connessioni. La configurazione sopra dà per scontato di poter aprire la porta sul router; non sempre è così. Tre scenari:

  1. Si controlla il router. Si inoltra la porta dei trasporti (port forwarding o pinhole IPv6). Caso semplice.
  2. Non si controlla il router, o c'è NAT. Le reti di overlay sono progettate per questo. I2P usa gli introducer e l'hole punching di SSU2: un router «firewalled» si fa presentare da peer terzi (gli introducer) e stabilisce connessioni bidirezionali che poi riusa. A differenza di un relay Tor, un router I2P dietro NAT partecipa e pubblica lo stesso i propri servizi: spesso non serve altro. L'analogo in Tor sono i bridge e i relay.
  3. NAT simmetrico o CGNAT aggressivo. Qui hole punching e introducer possono non bastare, perché la porta esterna cambia a ogni peer e il nodo non riesce a pubblicare i propri LeaseSet. Due vie d'uscita: l'IPv6, che spesso scavalca del tutto la CGNAT dando un recapito diretto; oppure frontare il servizio tramite un VPS economico con un tunnel inverso cifrato (è il VPS a ricevere, mentre il nodo tiene una connessione in uscita verso di esso). Attenzione: il VPS vede il punto d'ingresso, quindi va trattato come non fidato e usato come semplice inoltro, mai come deposito di chiavi o dati.

Sotto una censura nazionale (il tipo di DPI del cosiddetto Great Firewall) l'avversario non si limita a bloccare porte: fa ispezione profonda dei pacchetti, probing attivo e blocco degli endpoint. La raggiungibilità non è più questione di aprire porte ma di non farsi classificare.

Va sfatato un equivoco diffuso: né Tor né I2P «spoofano» i pacchetti nel senso di forgiare l'indirizzo IP sorgente. Con un sorgente falso non si riceverebbero le risposte di una connessione bidirezionale: non servirebbe a nulla per offrire un servizio. Ciò che fanno davvero è offuscare il traffico e usare punti d'ingresso non elencati. Gli strumenti reali:

  • In Tor: bridge non pubblici più i pluggable transport: obfs4 rende il flusso indistinguibile da rumore casuale, meek e il domain fronting lo fanno sembrare HTTPS verso una grande CDN, Snowflake usa WebRTC tramite volontari.
  • In I2P: i trasporti NTCP2 e SSU2 sono già offuscati (appaiono casuali) e non c'è una directory centrale da bloccare; il punto debole resta il reseed, da fare via Tor, proxy o da un bundle firmato.
  • Ricerca avanzata: il decoy routing / refraction networking (TapDance, Conjure) fa sembrare che il traffico vada verso un sito innocuo mentre una «stazione» presso un ISP collaborante lo devia verso la destinazione coperta. È il concetto più vicino a «far credere che i pacchetti vadano altrove», ma richiede un ISP cooperante e non è alla portata del singolo.

In pratica, per un nodo sotto censura: esporre il servizio come eepsite o onion (mai sul clear web), fare il bootstrap da un canale alternativo e, se il nodo deve comunque uscire, incapsularne il traffico in un pluggable transport, in un bridge o in un VPS front offuscato.

I2P rispetto a Tor

In sintesi, i due modelli si completano più di quanto si escludano:

  • Infrastruttura: Tor dipende da directory authority centrali; I2P da una NetDB distribuita → I2P più resistente al blocco dell'infrastruttura.
  • Instradamento: circuiti bidirezionali (Tor) contro tunnel unidirezionali (I2P); onion contro garlic.
  • Offuscamento: Tor "in chiaro" è riconoscibile e serve obfs4 via bridge; I2P ha NTCP2/SSU2 offuscati di default.
  • Caso d'uso: Tor eccelle nell'uscita verso il clear web; I2P nei servizi interni (eepsite) e nel traffico che resta in rete.
  • Insieme di anonimato: la rete Tor è molto più grande e più studiata dal mondo accademico; I2P è più piccola, quindi con un insieme di anonimato inferiore ma con meno punti centrali da colpire.

Per Tutanum la divisione dei compiti è netta: I2P è la rete ufficiale per i servizi interni, con il sito pubblicato come eepsite, mentre Tor viene usato per l'uscita verso il web in chiaro tramite gli exit node. Resta possibile, per aumentare raggiungibilità e ridondanza, pubblicare il servizio anche come onion service Tor.

Possibili attacchi alla rete I2P

Come per Tor, gli attacchi qui sotto sono documentati nella letteratura (in particolare Egger et al., "Practical Attacks Against the I2P Network") e sono riportati per capire da cosa un nodo Tutanum deve difendersi. Molte famiglie sono analoghe a quelle di Tor, riadattate alla NetDB e ai tunnel unidirezionali.

Attacco Sybil

L'avversario immette in rete un gran numero di router controllati per aumentare la propria quota, soprattutto tra i floodfill, così da influenzare la NetDB. La richiesta di banda/uptime per diventare floodfill e la rotazione giornaliera della chiave di routing alzano il costo dell'attacco.

Mitigazione: Non ingrossare involontariamente la superficie e sfruttare le euristiche del router:

  • Non diventare floodfill se non con banda e uptime elevati e stabili.
  • Tenere i2pd aggiornato (migliora il rilevamento di router sospetti) e attiva la blocklist.
  • Affidarsi alla rotazione giornaliera della chiave, che impedisce di prenotare posizioni nella NetDB.
# i2pd.conf floodfill = false # restare un router normale, non un floodfill [limits] transittunnels = 2500

PoC di verifica: Confermare di non essere floodfill: nella console web (http://127.0.0.1:7070) la voce "Router caps" non deve contenere la f.

grep -i '^floodfill' ~/.i2pd/i2pd.conf # deve risultare false o assente

Attacco eclipse

Variante mirata del Sybil: l'avversario piazza i propri floodfill "attorno" alla chiave di una destinazione per controllarne le ricerche di LeaseSet e isolarla. La rotazione giornaliera della chiave (SHA256(hash || data)) impedisce di prenotare in anticipo la posizione, e le blocklist dei floodfill malevoli aiutano.

Mitigazione: La rotazione della chiave dipende dalla data: un orologio sballato la vanifica. Mantenere il tempo sincronizzato e diversificare le fonti di NetDB:

  • Tenere l'orologio corretto: è la condizione perché la rotazione giornaliera funzioni. Sul nodo l'ora arriva attraverso Tor, non da NTP in chiaro (vedi Orologio).
  • Usare più server di reseed, così da non dipendere da un'unica vista della rete all'avvio.
# i2pd.conf [reseed] urls = https://reseed.i2p-projekt.de/,https://reseed2.i2p.net/,https://i2p.novg.net/

PoC di verifica: Controllare che l'orologio sia sincronizzato (un drift di minuti compromette la difesa):

doas /usr/local/sbin/ora-da-tor # nodo Tutanum: scarto rispetto alla mediana di tre onion service chronyc tracking # dove si usa chrony con NTS

Manipolazione del NetDB (floodfill malevoli)

È il cuore del lavoro di Egger et al.: floodfill ostili che memorizzano, negano o falsificano LeaseSet e RouterInfo possono censurare selettivamente una destinazione o raccogliere informazioni utili a deanonimizzarla osservando chi ne richiede il LeaseSet.

Mitigazione: Ridurre ciò che un floodfill ostile può leggere e sfruttare la ridondanza:

  • Pubblicare un LeaseSet cifrato (ECIES-X25519): i floodfill non ne leggono i gateway in chiaro.
  • Ridondanza dei floodfill onesti interrogati e verifica incrociata delle risposte (gestita dal router), più la rotazione delle chiavi.
# tunnels.conf della Destination del servizio i2cp.leaseSetEncType = 4 # LeaseSet con cifratura ECIES-X25519 i2cp.leaseSetType = 5 # Encrypted LeaseSet 2

PoC di verifica: Nel pannello "I2P tunnels" della console web il tunnel del servizio deve risultare con tipo di LeaseSet cifrato (ECIES), non in chiaro.

Attacchi di correlazione del traffico

Chi osserva o controlla il gateway di un tunnel outbound e l'endpoint/gateway coinvolti dall'altra parte può tentare di correlare tempi e volumi, come nella correlazione end-to-end su Tor. I tunnel unidirezionali e il garlic routing complicano l'analisi, ma non la rendono impossibile contro un avversario che vede entrambi i lati.

Mitigazione: Allungare i tunnel, introdurre varianza di lunghezza e aumentare la ridondanza rende molto più difficile posizionarsi su entrambi i capi e correlare:

# tunnels.conf inbound.length = 3 inbound.lengthVariance = 1 # lunghezza casuale fra 2 e 4 hop inbound.quantity = 5 # più tunnel paralleli outbound.length = 3 outbound.lengthVariance = 1 outbound.quantity = 5

Attacchi di intersezione e del predecessore

Poiché i tunnel vengono ricostruiti di continuo, un avversario che gestisce dei router e osserva per lungo tempo quali nodi ricorrono come "precedenti" rispetto a una destinazione può, statisticamente, restringere il campo sull'originatore.

Mitigazione: La varianza nella lunghezza e i tunnel a vita più lunga per i servizi riducono il segnale statistico accumulabile nel tempo; conviene anche non moltiplicare le ricostruzioni inutilmente.

# tunnels.conf (servizio stabile) inbound.length = 3 inbound.lengthVariance = 1 outbound.length = 3 outbound.lengthVariance = 1 # ridondanza sufficiente (quantity) per non forzare continue ricostruzioni

Attacco DoS

Comprende l'inondazione dei tunnel di transito, lo spam di record verso i floodfill e in generale l'esaurimento delle risorse dei nodi.

Mitigazione: Imporre tetti sia a livello di i2pd sia di sistema operativo e monitorare:

  • Limitare i tunnel di transito, i descrittori e la banda in i2pd.conf.
  • Imporre al processo i2pd limiti di memoria e di file aperti dal sistema operativo (login.conf su *BSD, unit systemd su Linux).
  • Monitorare tunnel di transito e banda dalla console web.
# i2pd.conf bandwidth = L # tetto di banda (L = 32 KB/s ... X = illimitato) [limits] transittunnels = 2500 # quanto traffico altrui si è disposti a far transitare openfiles = 8192 coresize = 0

PoC di verifica: Dalla console web (http://127.0.0.1:7070) controllare che i tunnel di transito e la banda restino entro i limiti impostati; su picchi anomali, abbassare i tetti.

Reti alternative

Tor e I2P non sono le uniche reti pensate per l'anonimato o la privacy. I2P è trattata a parte, nella sezione dedicata, perché è la rete scelta per i servizi di Tutanum; di seguito le altre alternative valutate e il motivo per cui sono state scartate.

Lokinet / Oxen

Il repository di Lokinet non riceve commit da oltre un anno e il progetto Oxen sta migrando verso Session. Soprattutto, il meccanismo per disincentivare i nodi malevoli si basa sui token Oxen: registrare un dominio ha un costo (dell'ordine di circa 5 $ per 10 anni). Dover pagare per esporre un servizio è un ostacolo che per Tutanum non va bene.

Reticulum

Reticulum non è orientata all'anonimato ma alla privacy, e si propone come alternativa al protocollo IP, di fatto come alternativa a internet stesso: al posto degli IP genera degli hash che garantiscono una cifratura end-to-end. Abbinarla a una cifratura onion offerta da una rete di anonimizzazione potrebbe essere interessante, ma il suo posto naturale è il progetto futuro della "rete alternativa ad internet", non l'hosting di un sito ora.

GNUnet

GNUnet è ancora in forte sviluppo e, per stessa ammissione del progetto, non è pronta per un uso che vada oltre quello degli sviluppatori.

Hyphanet

Hyphanet (ex Freenet) supporta solo siti statici, mentre il sito di Tutanum è dinamico.

IPFS

IPFS non è una rete anonima: espone informazioni sui peer (dettagli).

Conclusione

La scelta per Tutanum è quindi I2P come rete ufficiale per i servizi, con il sito pubblicato come eepsite e tutte le mitigazioni descritte, mentre Tor copre l'uscita verso il web in chiaro ed eventualmente una pubblicazione aggiuntiva come onion service. Reticulum resta riservata al progetto della rete alternativa ad internet.

Reti radio mesh: una possibile uscita da internet

Tutte le reti viste finora, Tor e I2P comprese, poggiano comunque sul cavo e sulla fibra di qualcun altro, cioè su quella stessa infrastruttura fisica di proprietà di operatori e governi che si vorrebbe evitare, cosicché la ricerca di un mezzo davvero indipendente porta prima o poi a guardare verso la radio, dove Meshtastic si presenta come la risposta oggi più matura e accessibile, un firmware libero che gira su microcontrollori da pochi euro (ESP32, nRF52, RP2040) collegati a un modulo radio LoRa e che fa di ciascun apparecchio un nodo di una maglia nella quale ogni dispositivo ripete i messaggi degli altri, di modo che il traffico attraversi il territorio saltando di nodo in nodo senza bisogno di alcun operatore, di alcuna SIM, di alcuna dorsale e di alcun satellite, configurando quella rete alternativa ad internet che il progetto tiene tra i propri sviluppi futuri e che qui conviene illustrare nei suoi fondamenti teorici prima ancora che nelle sue implementazioni.

Il cuore di LoRa, acronimo di Long Range, sta nella modulazione chirp spread spectrum brevettata da Semtech, nella quale ogni simbolo viene trasmesso come una rampa di frequenza che spazza l'intera banda, guadagnando in questo modo un notevole guadagno di processo che permette al ricevitore di estrarre il segnale perfino quando esso giace parecchi decibel sotto il rumore termico, e sono proprio questa sensibilità estrema e la lentezza deliberata della trasmissione a regalare portate di molti chilometri con potenze dell'ordine delle decine di milliwatt, al prezzo di una capacità modestissima governata da tre parametri, lo spreading factor che fissa la lunghezza del chirp, la larghezza di banda e il coding rate della correzione d'errore, il cui gioco reciproco determina insieme la robustezza del collegamento e il tempo che il pacchetto occupa l'aria, grandezza quest'ultima che vincola ogni cosa perché nelle bande a libero uso il regolatore impone un ciclo di lavoro massimo, tipicamente l'uno per cento in Europa sui 868 MHz, cosicché un nodo che impieghi due secondi a dire quaranta byte si ritrova a poter parlare appena diciotto volte in un'ora, come il primo PoC rende evidente calcolando a un tempo la durata della trasmissione, la soglia di ricezione e la quota oraria concessa.

import math def tempo_in_aria(payload, sf, bw, cr=1, preambolo=8, crc=True, header=True, ldro=None): """Tempo in aria di un pacchetto LoRa, in secondi (Semtech AN1200.13). payload: byte utili, sf: spreading factor da 7 a 12, bw: banda in Hz, cr: coding rate da 1 a 4 cioe' da 4/5 a 4/8.""" t_sym = (2 ** sf) / bw # durata di un simbolo if ldro is None: # ottimizzazione a basso data rate ldro = 1 if t_sym > 16e-3 else 0 t_preambolo = (preambolo + 4.25) * t_sym num = 8 * payload - 4 * sf + 28 + 16 * (1 if crc else 0) - 20 * (0 if header else 1) den = 4 * (sf - 2 * ldro) n = 8 + max(math.ceil(num / den) * (cr + 4), 0) return t_preambolo + n * t_sym def sensibilita(sf, bw, nf=6): """Soglia di ricezione in dBm: rumore termico piu' figura di rumore del ricevitore piu' il minimo rapporto segnale/rumore che quel SF regge.""" snr = {7: -7.5, 8: -10, 9: -12.5, 10: -15, 11: -17.5, 12: -20}[sf] return -174 + 10 * math.log10(bw) + nf + snr for sf in (7, 10, 12): t = tempo_in_aria(payload=40, sf=sf, bw=125e3) print(f"SF{sf}: {t*1000:7.1f} ms per 40 byte, " f"max {3600*0.01/t:5.0f} pacchetti/ora col duty cycle UE dell'1%, " f"sensibilita' {sensibilita(sf, 125e3):6.1f} dBm") # SF7: 82.2 ms per 40 byte, max 438 pacchetti/ora, sensibilita' -124.5 dBm # SF10: 534.5 ms per 40 byte, max 67 pacchetti/ora, sensibilita' -132.0 dBm # SF12: 1974.3 ms per 40 byte, max 18 pacchetti/ora, sensibilita' -137.0 dBm

Sopra questo livello fisico Meshtastic adotta un instradamento a inondazione gestita, il managed flood, nel quale un pacchetto immesso da un nodo viene ripetuto una sola volta da ciascuno di quelli che lo ascoltano, mentre un contatore di salti, l'hop limit, cala a ogni rimbalzo fino a spegnere la propagazione, meccanismo tanto elementare quanto rivelatore perché il secondo PoC, simulando una maglia di sessanta nodi sparsi a caso, mostra come la copertura cresca con il numero di salti consentiti ma al prezzo di un numero di ritrasmissioni che esplode, il che spiega perché una simile rete regga bene le comunità locali e si degradi invece rapidamente quando la si voglia far crescere oltre misura, limite che lungi dall'essere un difetto si accorda in pieno con il valore dell'antiscalabilita', giacché una rete di piccoli nodi indipendenti, ognuno comprensibile e gestibile da una sola persona, è esattamente ciò che si desidera.

import random, collections def mesh_casuale(n=60, raggio=0.18, lato=1.0, seme=1): """Dispone n nodi a caso su un quadrato e collega quelli che si sentono, cioe' quelli a distanza inferiore al raggio di copertura della radio.""" r = random.Random(seme) nodi = [(r.random() * lato, r.random() * lato) for _ in range(n)] adiac = collections.defaultdict(list) for i in range(n): for j in range(i + 1, n): dx, dy = nodi[i][0] - nodi[j][0], nodi[i][1] - nodi[j][1] if dx * dx + dy * dy <= raggio * raggio: adiac[i].append(j) adiac[j].append(i) return adiac def inonda(adiac, sorgente, hop_limit=3): """Managed flood come in Meshtastic: ogni nodo ripete il messaggio una sola volta e ad ogni salto l'hop limit cala, finche' non si esaurisce.""" visti = {sorgente} coda = collections.deque([(sorgente, hop_limit)]) ritrasmissioni = 0 while coda: nodo, hop = coda.popleft() if hop <= 0: continue ritrasmissioni += 1 for vicino in adiac[nodo]: if vicino not in visti: visti.add(vicino) coda.append((vicino, hop - 1)) return len(visti), ritrasmissioni adiac = mesh_casuale() for hop in (2, 3, 5, 8): coperti, tx = inonda(adiac, sorgente=0, hop_limit=hop) print(f"hop_limit={hop}: raggiunti {coperti}/60 nodi con {tx} ritrasmissioni") # hop_limit=2: raggiunti 6/60 nodi con 4 ritrasmissioni # hop_limit=3: raggiunti 11/60 nodi con 6 ritrasmissioni # hop_limit=5: raggiunti 28/60 nodi con 15 ritrasmissioni # hop_limit=8: raggiunti 53/60 nodi con 45 ritrasmissioni

Sul piano materiale un nodo di una simile maglia si riduce a pochi elementi che conviene conoscere uno per uno, perché è dal loro comportamento fisico che discendono tanto le prestazioni quanto le vulnerabilità viste finora, a cominciare dal transceiver LoRa vero e proprio, quasi sempre un chip Semtech della famiglia SX127x di prima generazione oppure dei più recenti SX126x e del loro derivato LLCC68, che integrano l'oscillatore, il sintetizzatore di frequenza, il modulatore chirp e l'amplificatore di potenza capace di spingere il segnale fino a circa venti decibel riferiti al milliwatt, chip che il microcontrollore pilota via SPI e che a loro volta si appoggiano a un cervello scelto di solito tra l'ESP32, dotato di WiFi e Bluetooth ma affamato di corrente, l'nRF52840 della Nordic, molto più parco e con Bluetooth a basso consumo integrato, e il più spartano RP2040, sicché le schede che li combinano, dalle Heltec LoRa32 alle LILYGO della serie T-Beam che aggiungono un ricevitore GPS e il portabatteria per una cella 18650, dai moduli RAK WisBlock pensati a mattoncini fino alle T-Echo a bassissimo consumo con schermo a inchiostro elettronico, si distinguono soprattutto per quali di questi componenti mettono insieme e per quanta energia richiedono.

Attorno al chip il resto della catena a radiofrequenza decide la portata reale assai più della potenza nominale, giacché un filtro SAW all'ingresso protegge il ricevitore dalle bande vicine, un eventuale amplificatore a basso rumore ne migliora la sensibilità, ma è l'antenna a comandare, e qui la fisica non lascia scampo perché la lunghezza di uno stilo a quarto d'onda è fissata dalla frequenza, cosicché i circa otto centimetri che bastano sugli 868 MHz diventano il doppio sui 433 MHz, e perché il collegamento a lunga distanza pretende, oltre alla linea di vista ottica, che resti sgombra anche la prima zona di Fresnel, quel fuso attorno al raggio diretto che su una tratta di qualche chilometro si allarga a decine di metri e che ostacoli e terreno non devono invadere, come il PoC seguente calcola insieme alla distanza dell'orizzonte radio, la quale cresce con la radice dell'altezza delle antenne e spiega perché un nodo collocato in alto, su un tetto o su un traliccio, valga molti nodi a terra.

import math c = 299_792_458.0 def quarto_onda(f_hz, fattore_velocita=0.95): """Lunghezza di uno stilo a quarto d'onda, in metri.""" return fattore_velocita * (c / f_hz) / 4 def raggio_fresnel(f_hz, d1, d2): """Raggio della prima zona di Fresnel nel punto che dista d1 e d2 dai due estremi.""" lam = c / f_hz return math.sqrt(lam * d1 * d2 / (d1 + d2)) def orizzonte_radio(h1, h2): """Distanza dell'orizzonte radio in km, con le altezze delle antenne in metri.""" return 4.12 * (math.sqrt(h1) + math.sqrt(h2)) for f in (433e6, 868e6): print(f"{f/1e6:3.0f} MHz: stilo a quarto d'onda {quarto_onda(f)*100:5.1f} cm, " f"prima zona di Fresnel a meta' di una tratta di 5 km {raggio_fresnel(f, 2500, 2500):5.1f} m") print(f"orizzonte radio con antenne a 10 m e 2 m: {orizzonte_radio(10, 2):.1f} km") # 433 MHz: stilo a quarto d'onda 16.4 cm, prima zona di Fresnel 29.4 m # 868 MHz: stilo a quarto d'onda 8.2 cm, prima zona di Fresnel 20.8 m # orizzonte radio con antenne a 10 m e 2 m: 18.9 km

Due componenti meritano un'attenzione particolare perché legano l'hardware alle minacce già descritte, e il primo è l'oscillatore di riferimento, dato che un semplice quarzo deriva con la temperatura di parecchie parti per milione e sposta così la portante, mentre un oscillatore compensato in temperatura, il TCXO di cui i moduli SX126x migliori sono dotati, tiene la frequenza stabile entro frazioni di parte per milione, il che conta due volte, sia perché quella stessa deriva è parte dell'offset di frequenza della portante che alimenta il riconoscimento d'impronta descritto più avanti, sia perché la marcatura dei tempi che rende possibile la localizzazione per differenza di arrivo dipende dalla qualità del riferimento temporale, tanto che molti nodi si sincronizzano via GPS, soluzione che però aggiunge un ricevitore sempre affamato di energia e un ulteriore appiglio, e il secondo è proprio il bilancio energetico, perché un nodo deve spesso vivere di batteria e di un piccolo pannello solare, e allora il ciclo di lavoro imposto dalla legge si rivela un alleato involontario dell'autonomia, come il PoC conclusivo mostra confrontando un nodo che dorme quasi sempre e si sveglia solo per una breve trasmissione, capace di durare quasi un anno su una singola cella al litio, con lo stesso nodo tenuto in ascolto GPS continuo, la cui autonomia precipita a pochi giorni.

def autonomia(batteria_mAh, i_dormienza_mA, i_tx_mA, t_tx_s, periodo_s, i_extra_mA=0): """Corrente media e autonomia di un nodo che trasmette t_tx secondi ogni periodo.""" duty = t_tx_s / periodo_s i_media = i_dormienza_mA + i_extra_mA + (i_tx_mA - i_dormienza_mA) * duty return i_media, batteria_mAh / i_media / 24 # corrente media in mA e giorni for descrizione, extra in (("solo radio", 0.0), ("con GPS sempre acceso", 30.0)): i, giorni = autonomia(3400, 0.05, 120, 2.0, 600, extra) print(f"{descrizione:22}: corrente media {i:6.2f} mA, autonomia {giorni:5.0f} giorni su una 18650") # solo radio : corrente media 0.45 mA, autonomia 315 giorni su una 18650 # con GPS sempre acceso : corrente media 30.45 mA, autonomia 5 giorni su una 18650

Resta infine l'hardware che apre la strada agli sviluppi già evocati, cioè la radio definita dal software, perché apparati come l'economico RTL-SDR in sola ricezione e, in ricetrasmissione, HackRF One, LimeSDR e PlutoSDR portano la modulazione dentro il calcolatore e liberano il nodo dal vincolo di una sola banda e di un solo schema, consentendo in linea di principio di spostarsi tra frequenze e modulazioni per schivare le interferenze e rendere il segnale più sfuggente, al prezzo di consumi e di una complessità ben maggiori di quelli di un modulo LoRa dedicato, e offrendo nel contempo lo strumento con cui un avversario cattura i campioni grezzi del segnale per estrarne l'impronta analogica o per misurarne i tempi di arrivo, mentre sul fronte opposto le contromisure fisiche tornano a essere quelle della sezione sulla compromissione elettromagnetica, cioè la schermatura, il contenimento delle emissioni fuori banda dovute alle non linearità dell'amplificatore e la cura del front-end, a conferma che la sicurezza di una rete radio si gioca per intero già nel suo stadio analogico.

Giunti a questo punto occorre affrontare il nodo della cifratura, perché Meshtastic protegge il contenuto dei messaggi, cifrando i canali con AES-256 in modalità CTR e i messaggi diretti con la crittografia a chiave pubblica X25519 abbinata ad AES-CCM, e tuttavia lascia in chiaro l'intera intestazione del pacchetto, vale a dire l'identificativo del mittente, quello del destinatario, l'id del pacchetto, l'hop limit e il byte che individua il canale, informazioni che chiunque disponga di una radio legge integralmente senza possedere alcuna chiave e dalle quali, come il terzo PoC dimostra ricostruendo il grafo delle coppie che dialogano, si ricava quel reticolo di relazioni, tempi, frequenze e lunghezze dei messaggi che costituisce i metadati, i quali raccontano quasi tutto di una comunità anche quando ogni parola resta illeggibile.

import os from dataclasses import dataclass @dataclass class PacchettoMesh: mittente: int # id del nodo, in chiaro destinatario: int # id del nodo, in chiaro (0xffffffff = broadcast) id_pacchetto: int # in chiaro, usato anche come parte del nonce hop_limit: int # in chiaro canale_hash: int # byte che individua il canale, in chiaro payload: bytes # questo soltanto e' cifrato (AES-256-CTR o X25519+AES-CCM) def intestazione_visibile(p): """Tutto cio' che chiunque abbia una radio legge senza possedere alcuna chiave.""" return (f"da {p.mittente:08x} a {p.destinatario:08x} " f"canale#{p.canale_hash:02x} id={p.id_pacchetto:08x} " f"hop={p.hop_limit} ({len(p.payload)} byte cifrati)") traffico = [ PacchettoMesh(0xa1b2c3d4, 0x55667788, 0x0001, 3, 0x08, os.urandom(32)), PacchettoMesh(0x55667788, 0xa1b2c3d4, 0x0002, 3, 0x08, os.urandom(18)), PacchettoMesh(0xa1b2c3d4, 0x55667788, 0x0003, 3, 0x08, os.urandom(41)), ] # L'intercettatore non legge una sola parola del contenuto, eppure ricostruisce # chi parla con chi, quando, quanto spesso e con quali lunghezze: il grafo sociale. grafo = collections.Counter() for p in traffico: print(intestazione_visibile(p)) grafo[(p.mittente, p.destinatario)] += 1 print("coppie osservate:", dict(grafo))

Da qui discende l'osservazione che darebbe a un simile sistema la sua piena sicurezza, e cioè che sarebbe davvero necessario cifrare l'intero stack ISO/OSI, occultando insieme al contenuto applicativo anche gli indirizzi di collegamento, la struttura stessa del pacchetto e idealmente persino la forma e la presenza del segnale sul livello fisico, cosicché all'osservatore non resti alcun appiglio né sul cosa né sul chi né sul quando, e qui si incontra lo scoglio che è insieme tecnico e politico, perché sulle bade a libero uso la legge consente di cifrare il contenuto, come Meshtastic già fa, ma vieta di nascondere gli identificativi di livello collegamento e circoscrive severamente potenza e ciclo di lavoro, mentre sulle bande radioamatoriali, cioè proprio quelle che offrirebbero la potenza e lo spettro per coprire distanze reali, il Regolamento delle radiocomunicazioni dell'ITU all'articolo 25 e, in Italia, il Codice delle comunicazioni elettroniche proibiscono espressamente la cifratura e l'occultamento del contenuto e obbligano l'operatore a trasmettere in chiaro identificandosi con il proprio nominativo, di modo che un sistema che cifri davvero tutto lo stack e che si estenda liberamente a qualunque frequenza e modulazione per sottrarsi alle interferenze e al riconoscimento esiste soltanto lontano da ogni regola, nel territorio che lo Stato bolla come radio pirata.

Resta allora vero che rinunciare ai ponti radio proprietari, e con essi ai satelliti proprietari, affidando la ripetizione del segnale tra i nodi a LoRa e alla maglia, è il sistema più libero che oggi si riesca a concepire, e che estendere l'impianto di Meshtastic a qualsiasi frequenza e a qualsiasi modulazione, scegliendole dinamicamente, gioverebbe senz'altro perché permetterebbe di schivare le bande congestionate e le interferenze e di rendere il segnale molto più difficile da seguire, eppure ancora una volta si frappone lo Stato che con la legge ostacola la nascita di un mezzo di comunicazione realmente libero, etichettando come radioamatori pirati le persone che osano adoperarlo, sicché la libertà tecnica del progetto si scontra qui con un confine normativo che il progetto può descrivere e criticare restando dal di qua dell'illegalità, studiandone cioè la teoria senza trasmettere fuori dalle regole.

Converrebbe tuttavia non illudersi che cifrare l'intero stack basti, poiché al di sotto di ogni bit sopravvive il livello analogico, dove ciascun trasmettitore porta impressa un'impronta involontaria fatta dell'offset di frequenza della portante, dello sbilanciamento tra i rami in fase e in quadratura e delle non linearità del suo amplificatore di potenza, imperfezioni minime che la fabbricazione rende diverse in ogni singolo pezzo e che una rete neurale addestrata sui campioni grezzi del segnale sa riconoscere identificando l'apparato a prescindere da qualunque identificativo logico e da qualunque cifratura, attacco noto come RF fingerprinting al quale la ricerca oppone contromisure come il disturbo amico a bassa potenza descritto in Preventing Radio Fingerprinting through Friendly Jamming, nel quale il trasmettitore somma al proprio segnale un rumore controllato che annega l'impronta pur lasciando intatto il tasso d'errore dei bit e porta così il riconoscitore verso l'indistinguibilità tra più apparati, principio che il quarto PoC illustra generando impronte sintetiche per cinque trasmettitori, addestrando un classificatore e mostrando come la sua accuratezza, prossima al novanta per cento sulle catture pulite, scivoli verso il venti per cento del puro caso man mano che il disturbo cresce.

import numpy as np rng = np.random.default_rng(0) N = 5 # trasmettitori presenti nella rete # L'impronta analogica di un apparato: offset di frequenza della portante (CFO), # sbilanciamento dei rami I e Q e non linearita' dell'amplificatore di potenza. # Sono tre grandezze che la fabbricazione rende leggermente diverse in ogni pezzo. centri = rng.normal(0, 1, size=(N, 3)) def campioni(n_per_nodo, rumore): X, y = [], [] for k in range(N): X.append(centri[k] + rng.normal(0, rumore, size=(n_per_nodo, 3))) y += [k] * n_per_nodo return np.vstack(X), np.array(y) def classifica(centri_stimati, X): """Assegna ogni cattura al trasmettitore la cui impronta e' piu' vicina.""" distanze = ((X[:, None, :] - centri_stimati[None, :, :]) ** 2).sum(-1) return distanze.argmin(1) # L'avversario addestra il suo modello su catture quasi pulite. Xtr, ytr = campioni(400, rumore=0.25) centri_stimati = np.array([Xtr[ytr == k].mean(0) for k in range(N)]) # "rjp" e' la potenza relativa del disturbo amico aggiunto dal trasmettitore, # che sommandosi all'impronta la annega mantenendo intatto il bit error rate. for rjp in (0.0, 0.1, 0.5, 1.5): Xte, yte = campioni(200, rumore=0.25 + rjp) acc = (classifica(centri_stimati, Xte) == yte).mean() print(f"disturbo amico = {rjp:>3}: accuratezza {acc:5.1%} (caso casuale {1/N:.0%})") # disturbo amico = 0.0: accuratezza 92.6% (caso casuale 20%) # disturbo amico = 0.1: accuratezza 89.8% (caso casuale 20%) # disturbo amico = 0.5: accuratezza 68.3% (caso casuale 20%) # disturbo amico = 1.5: accuratezza 45.3% (caso casuale 20%)

Un secondo spettro che la sola cifratura non scaccia è la localizzazione fisica, perché quando più ricevitori ascoltano lo stesso pacchetto ne possono misurare le minime differenze nei tempi di arrivo e, incrociandole per multilaterazione, risalire alla posizione del nodo trasmittente con un'accuratezza che la letteratura sulla localizzazione in LoRaWAN colloca tra la decina e le poche centinaia di metri a seconda della densità dell'infrastruttura e, soprattutto, della risoluzione del marcatore temporale, giacché l'hardware LoRa comune marca i tempi al microsecondo, intervallo durante il quale la luce percorre circa trecento metri, ragione per cui chi dispone di ricevitori più precisi stringe drasticamente il cerchio, come mostrano sia l'indagine sulle prestazioni della localizzazione TDoA su LoRaWAN sia, sul versante della sincronizzazione, lo studio di Marguerite Delcourt e Jean-Yves Le Boudec dell'EPFL, TDOA Source-Localization Technique Robust to Time-Synchronization Attacks apparso sulle IEEE Transactions on Information Forensics and Security, che studiando la localizzazione di una sorgente passiva e non cooperativa quantifica quanto il metodo sia fragile al tempo, poiché bastano tre microsecondi di scarto introdotti su un solo ricevitore per spostare di circa novecento metri la differenza di cammino stimata e appena qualche microsecondo per collocare la sorgente a un chilometro dalla sua posizione reale, per giunta senza che l'analisi dei residui riesca ad accorgersi della manipolazione, come il quinto PoC rende tangibile simulando quattro gateway agli angoli di un quadrato di quattro chilometri e ritrovando il nodo per forza bruta, con un errore medio intorno ai duecentotrenta metri quando i tempi sono quantizzati al microsecondo che si riduce a poche decine di metri quando la risoluzione sale, da cui discendono come mitigazioni teoriche l'abbassare la potenza, il diradare e rendere irregolari le trasmissioni, il muoversi, il ridurre la ridondanza dei ricevitori amici e perfino l'introdurre di proposito quei disallineamenti temporali asimmetrici che, come lo stesso studio dimostra dal lato opposto per poi difendersene con una taratura su sorgente nota, spostano di chilometri la posizione dedotta da chi tenta la localizzazione, tutte misure che tornano però a scontrarsi con gli obblighi di identificazione e di trasmissione in chiaro già richiamati.

import numpy as np c = 299_792_458.0 # velocita' della luce, m/s gateway = np.array([[0, 0], [4000, 0], [0, 4000], [4000, 4000]], float) vero = np.array([1200.0, 2600.0]) # posizione reale del nodo, da ritrovare def simula_tempi(vero, gateway, risoluzione=1e-6, rng=None): """Istanti di arrivo ai gateway, quantizzati al timestamp hardware (un microsecondo, cioe' circa 300 metri di luce) e sporcati dal jitter.""" rng = rng or np.random.default_rng() t = np.linalg.norm(gateway - vero, axis=1) / c return np.round(t / risoluzione) * risoluzione + rng.normal(0, risoluzione, len(t)) def localizza(t, gateway, lato=4000, passo=20): """Multilaterazione per forza bruta: cerca il punto che meglio spiega le differenze dei tempi di arrivo rispetto al primo gateway.""" dt = (t - t[0]) * c assi = np.arange(0, lato + passo, passo) migliore, punto = None, None for x in assi: for y in assi: d = np.linalg.norm(gateway - (x, y), axis=1) errore = np.sum(((d - d[0]) - dt) ** 2) if migliore is None or errore < migliore: migliore, punto = errore, (x, y) return np.array(punto) rng = np.random.default_rng(1) for risoluzione in (1e-6, 1e-7): errori = [np.linalg.norm(localizza(simula_tempi(vero, gateway, risoluzione, rng), gateway) - vero) for _ in range(12)] print(f"timestamp {risoluzione*1e9:5.0f} ns: errore medio di localizzazione {np.mean(errori):6.1f} m") # timestamp 1000 ns: errore medio di localizzazione 229.3 m # timestamp 100 ns: errore medio di localizzazione 36.6 m

Questa tensione fra ciò che è tecnicamente possibile e ciò che è legalmente concesso ha una genesi precisa, costituendo il punto d'arrivo di una parabola che conviene ricostruire, perché nei primi anni Duemila, e segnatamente dopo l'undici settembre del 2001 con lo USA PATRIOT Act e con i programmi statunitensi di raccolta massiva come STELLARWIND, la sorveglianza di popolazione fu edificata di nascosto, al riparo da ogni dibattito pubblico e spesso ai margini o al di fuori della legalità, finché le rivelazioni di Edward Snowden nel 2013 non ne squadernarono l'impalcatura, da PRISM a XKEYSCORE a Tempora fino al programma Bullrun dedicato a indebolire la crittografia, mostrando al mondo una sorveglianza di massa tanto estesa quanto priva di mandato dichiarato, laddove dal 2013 a oggi il moto si è invertito e la medesima sorveglianza, anziché restare occulta, viene scritta nelle leggi, discussa nei parlamenti e votata alla luce del sole, in una normalizzazione politica che procede per provvedimenti successivi.

Lungo questa seconda fase si allineano il regolamento europeo per il contrasto degli abusi sui minori, noto come Chat Control, che vorrebbe imporre la scansione dei messaggi sui dispositivi stessi, il cosiddetto client-side scanning, minando alla radice la cifratura end-to-end e il cui iter, raccontato puntualmente da Patrick Breyer, dopo il naufragio del negoziato fra le istituzioni nel giugno 2026 ha visto reintrodurre in luglio la versione provvisoria della norma, prolungando fino al 2028 la scansione volontaria dei contenuti; e accanto a esso corrono il pacchetto ProtectEU con la sua tabella di marcia verso l'accesso ai dati cifrati e il rafforzamento di Europol, il sistema biometrico europeo di ingressi e uscite EES entrato in funzione nell'ottobre 2025, i dispositivi di verifica dell'età e il portafoglio digitale europeo costruito sul regolamento eIDAS 2, le identità digitali nazionali approvate per referendum in Svizzera nel settembre 2025 e annunciate come obbligatorie nel Regno Unito, fino all'inasprimento del Digital Services Act, un insieme di misure che, convergendo, realizza per via legislativa ed esplicita ciò che vent'anni prima si faceva in segreto, confermando quanto Tutanum pone tra i propri valori, ossia che privacy, anonimato e sicurezza vanno difesi come diritti proprio mentre la legge li erode.

In questo quadro la radio mesh non è l'unica strada immaginata, e vale la pena ricordare AirChat, il progetto diffuso nel 2014 dal collettivo lulzlabs che impiega ricetrasmittenti FM economiche in VHF e UHF pilotando come modem audio il software Fldigi via XML-RPC e incapsulando i dati in pacchetti, i Lulzpacket, i cui indirizzi derivano dall'hash di chiavi asimmetriche anziché da identificativi hardware, con cifratura opzionale e con passerelle verso internet, Tor e le piattaforme sociali, un sistema oggi fermo nello sviluppo eppure prezioso sul piano concettuale perché rivendica apertamente il diritto di cifrare a dispetto dei divieti e dimostra che già con due radio da quaranta dollari si giocano partite a scacchi e si trasmettono ordini a centottanta chilometri di distanza; accanto a esso si colloca Reticulum, lo stack crittografico già discusso tra le reti alternative, pensato per funzionare su qualsiasi mezzo, cavo, radio o LoRa, offrendo di fabbrica indirizzi cifrati e instradamento indipendente dal protocollo IP.

Gli sviluppi possibili muovono da qui verso l'estensione della maglia alle onde corte per guadagnare portate intercontinentali per riflessione ionosferica, verso l'adozione di radio interamente definite dal software che rendano agile la scelta di frequenza e modulazione e che permettano di variarle per eludere interferenze e riconoscimento, verso la sovrapposizione alla maglia di un instradamento a cipolla che aggiunga l'anonimato alla semplice riservatezza del contenuto, e verso l'integrazione con iop perché la condivisione dei dati tracciati con git possa viaggiare anche sul mezzo radio quando ogni altra via sia chiusa, direzioni tutte coerenti con l'idea di una rete che, lontano dai ponti e dai satelliti proprietari, restituisca alle persone un mezzo di comunicazione davvero proprio.