<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Firewall on My personal blog</title>
        <link>https://www.matteobianchi.eu/tags/firewall/</link>
        <description>Recent content in Firewall on My personal blog</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en</language>
        <lastBuildDate>Tue, 15 Sep 2026 09:00:00 +0200</lastBuildDate><atom:link href="https://www.matteobianchi.eu/tags/firewall/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>Anatomia di un DDoS</title>
        <link>https://www.matteobianchi.eu/p/ddos-anatomy-and-mitigation/</link>
        <pubDate>Tue, 15 Sep 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/ddos-anatomy-and-mitigation/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/ddos-anatomy-and-mitigation/cover.png" alt="Featured image of post Anatomia di un DDoS" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;La riservatezza e l&amp;rsquo;integrità si proteggono con la crittografia. La &lt;strong&gt;disponibilità&lt;/strong&gt; no: non
esiste una chiave che impedisca a un milione di richieste di saturare un server. Il DDoS
(Distributed Denial of Service) attacca proprio questa terza gamba — la minaccia T4 del
&lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/threat-modeling-networks/&#34; &gt;threat model&lt;/a&gt; — e lo fa con la forza bruta
distribuita su migliaia di macchine.&lt;/p&gt;
&lt;p&gt;È anche il capitolo dove la verità è scomoda: contro un attacco volumetrico grande, da soli non si
può fare quasi nulla. Capire &lt;strong&gt;perché&lt;/strong&gt; è il primo passo per difendersi bene.&lt;/p&gt;
&lt;h2 id=&#34;tre-famiglie-tre-bersagli&#34;&gt;Tre famiglie, tre bersagli
&lt;/h2&gt;&lt;pre class=&#34;mermaid&#34;&gt;
  flowchart TD
    DDoS[DDoS] --&amp;gt; V[&amp;#34;Volumetrici&amp;lt;br/&amp;gt;saturano la banda&amp;#34;]
    DDoS --&amp;gt; P[&amp;#34;Di protocollo&amp;lt;br/&amp;gt;saturano le tabelle di stato&amp;#34;]
    DDoS --&amp;gt; A[&amp;#34;Applicativi (L7)&amp;lt;br/&amp;gt;saturano la CPU/il DB del server&amp;#34;]
    V --&amp;gt; V1[&amp;#34;UDP/DNS/NTP flood&amp;lt;br/&amp;gt;amplificazione&amp;#34;]
    P --&amp;gt; P1[&amp;#34;SYN flood&amp;lt;br/&amp;gt;connessioni mai completate&amp;#34;]
    A --&amp;gt; A1[&amp;#34;HTTP flood&amp;lt;br/&amp;gt;richieste &amp;#39;costose&amp;#39; ripetute&amp;#34;]
    style V fill:#fde2e4,stroke:#e63946
    style P fill:#fde2e4,stroke:#e63946
    style A fill:#fde2e4,stroke:#e63946
&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Volumetrici&lt;/strong&gt;: riempiono la banda in ingresso. Si misurano in Gbit/s o Tbit/s. Se il tubo è
pieno, nessuna regola locale aiuta: il traffico legittimo non arriva nemmeno.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Di protocollo&lt;/strong&gt;: non serve banda, serve esaurire una risorsa. Il SYN flood riempie la tabella
delle connessioni half-open.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Applicativi&lt;/strong&gt;: poche richieste, ma costose (una ricerca complessa, un login). Difficili da
distinguere dal traffico vero.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;il-syn-flood-e-le-syn-cookies&#34;&gt;Il SYN flood e le SYN cookies
&lt;/h2&gt;&lt;p&gt;Quando un client apre una connessione TCP, manda un SYN; il server risponde SYN-ACK e &lt;strong&gt;riserva
memoria&lt;/strong&gt; per la connessione half-open, in attesa dell&amp;rsquo;ACK finale. Il SYN flood invia molti SYN,
spesso con IP sorgente falsificato, e non completa mai l&amp;rsquo;handshake. La tabella si riempie, e i
client veri non entrano più.&lt;/p&gt;
&lt;p&gt;La difesa è elegante: le &lt;strong&gt;SYN cookies&lt;/strong&gt;. Il server non riserva memoria al SYN. Codifica lo stato
dentro il numero di sequenza del SYN-ACK (una funzione crittografica dei parametri della
connessione). Se l&amp;rsquo;ACK finale torna, il server lo decodifica e ricostruisce lo stato; se non
torna — come nel flood — non ha sprecato nulla.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# attivare le SYN cookies sul kernel Linux&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;sysctl -w net.ipv4.tcp_syncookies&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;lamplificazione-perché-un-attaccante-piccolo-fa-male&#34;&gt;L&amp;rsquo;amplificazione: perché un attaccante piccolo fa male
&lt;/h2&gt;&lt;p&gt;Gli attacchi volumetrici più grandi sfruttano l&amp;rsquo;&lt;strong&gt;amplificazione&lt;/strong&gt;. L&amp;rsquo;attaccante invia una piccola
query a un server pubblico (DNS, NTP, memcached), ma falsifica l&amp;rsquo;IP sorgente mettendoci quello
della &lt;strong&gt;vittima&lt;/strong&gt;. Il server risponde — alla vittima — con un pacchetto molto più grande.&lt;/p&gt;
&lt;p&gt;Il fattore di amplificazione è il rapporto:&lt;/p&gt;
&lt;p&gt;$$
F = \frac{\text{dimensione della risposta}}{\text{dimensione della richiesta}}
$$&lt;/p&gt;
&lt;p&gt;Per una query DNS &lt;code&gt;ANY&lt;/code&gt; una risposta può essere decine di volte più grande della domanda; con
memcached mal configurato si sono visti fattori oltre $10,000$. Con $F = 50$, un attaccante che
dispone di 1 Gbit/s di upload genera 50 Gbit/s verso la vittima. La potenza dell&amp;rsquo;attaccante viene
&lt;strong&gt;moltiplicata&lt;/strong&gt; dai server riflettori.&lt;/p&gt;
&lt;p&gt;L&amp;rsquo;amplificazione dipende da due difetti: server pubblici che rispondono a chiunque, e reti che
lasciano uscire pacchetti con IP sorgente falsificato (assenza di &lt;strong&gt;BCP 38 / source address
validation&lt;/strong&gt;). Entrambi vanno risolti da altri, non dalla vittima — ed è il motivo per cui il DDoS
è un problema collettivo.&lt;/p&gt;
&lt;h2 id=&#34;cosa-si-può-mitigare-da-soli-e-cosa-no&#34;&gt;Cosa si può mitigare da soli, e cosa no
&lt;/h2&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attacco&lt;/th&gt;
&lt;th&gt;Mitigabile localmente?&lt;/th&gt;
&lt;th&gt;Come&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SYN flood&lt;/td&gt;
&lt;td&gt;Sì, in gran parte&lt;/td&gt;
&lt;td&gt;SYN cookies, rate limiting sulla &lt;code&gt;new&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP flood (L7)&lt;/td&gt;
&lt;td&gt;In parte&lt;/td&gt;
&lt;td&gt;rate limiting per IP, CAPTCHA, cache&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volumetrico piccolo&lt;/td&gt;
&lt;td&gt;In parte&lt;/td&gt;
&lt;td&gt;rate limiting, filtri sul router&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Volumetrico grande&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;No&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;serve un servizio di mitigazione a monte (scrubbing)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Per i volumetrici grandi la realtà è semplice: se la banda in ingresso è satura, il filtro va fatto
&lt;strong&gt;prima&lt;/strong&gt; che il traffico arrivi al vostro tubo, cioè da un provider di scrubbing o da una CDN che
assorbe l&amp;rsquo;attacco sulla propria rete. È un servizio, non una configurazione.&lt;/p&gt;
&lt;p&gt;Localmente, il rate limiting di nftables (dal &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/stateful-firewalls-nftables/&#34; &gt;capitolo 04&lt;/a&gt;)
aiuta contro gli attacchi piccoli:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;table inet filter {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chain input {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        tcp dport 443 ct state new limit rate 50/second burst 100 packets accept
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        tcp dport 443 ct state new drop     # oltre la soglia: scarta i nuovi SYN
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;La riga evidenziata limita le &lt;strong&gt;nuove&lt;/strong&gt; connessioni a 50/s: le connessioni già stabilite
(&lt;code&gt;established&lt;/code&gt;) non sono toccate, quindi gli utenti legittimi collegati continuano a lavorare.&lt;/p&gt;
&lt;h2 id=&#34;lab&#34;&gt;Lab
&lt;/h2&gt;&lt;p&gt;Nel lab containerlab (traffico contenuto, è una dimostrazione del meccanismo, non un vero flood):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sul nodo server, attivate &lt;code&gt;tcp_syncookies&lt;/code&gt; e osservate &lt;code&gt;netstat -s | grep -i syn&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Dal nodo attacker, generate molti SYN con &lt;code&gt;hping3 -S --flood -p 443 &amp;lt;server&amp;gt;&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confrontate l&amp;rsquo;uso della tabella di connessione con e senza SYN cookies.&lt;/li&gt;
&lt;li&gt;Aggiungete il rate limiting nftables e misurate quante connessioni nuove passano.&lt;/li&gt;
&lt;/ol&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; perché falsificare l&#39;IP sorgente è utile all&#39;attaccante in un flood volumetrico ma non in un HTTP flood?&lt;/summary&gt;
&lt;p&gt;In un flood volumetrico o SYN l&#39;attaccante non ha bisogno di ricevere risposte: vuole solo
inondare. Falsificare l&#39;IP sorgente nasconde l&#39;origine e, nell&#39;amplificazione, dirige le risposte
dei riflettori verso la vittima. In un HTTP flood invece serve completare l&#39;handshake TCP e la
sessione TLS per inviare richieste HTTP vere: questo richiede un IP sorgente reale che riceve le
risposte, quindi lo spoofing non è possibile. È per questo che gli attacchi L7 usano botnet di
macchine reali compromesse, non pacchetti falsificati.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;Il DDoS attacca la disponibilità, che la crittografia non protegge. Alcune forme si mitigano da
soli — SYN cookies, rate limiting — ma i grandi attacchi volumetrici si fermano solo a monte, ed
esistono perché altre reti permettono lo spoofing e l&amp;rsquo;amplificazione. Difendersi bene significa sia
proteggere i propri server, sia non essere parte del problema (niente resolver aperti, source
address validation).&lt;/p&gt;
&lt;p&gt;Abbiamo attraversato tutti gli strati. Nel prossimo capitolo torniamo a un tema concreto: come
proteggere il traffico che attraversa reti non fidate, confrontando i due tunnel più usati.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prossimo nella serie:&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/ipsec-vs-wireguard/&#34; &gt;09 · IPsec contro WireGuard&lt;/a&gt; ·
&lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/network-security-roadmap/&#34; &gt;Torna alla roadmap&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Microsegmentazione: dividere la rete fino al singolo workload</title>
        <link>https://www.matteobianchi.eu/p/network-microsegmentation/</link>
        <pubDate>Sat, 05 Sep 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/network-microsegmentation/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/network-microsegmentation/cover.png" alt="Featured image of post Microsegmentazione: dividere la rete fino al singolo workload" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;La segmentazione tradizionale divide la rete in poche zone — uffici, server, ospiti — tipicamente
con &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/vlan-hopping-and-switch-hardening/&#34; &gt;VLAN&lt;/a&gt; e firewall tra di esse. Il
problema: &lt;em&gt;dentro&lt;/em&gt; una zona, tutto parla con tutto. Un attaccante che compromette un singolo
server nella zona &amp;ldquo;server&amp;rdquo; può muoversi liberamente verso gli altri. Questo &lt;strong&gt;movimento laterale&lt;/strong&gt;
è il modo in cui una singola macchina violata diventa una violazione dell&amp;rsquo;intera infrastruttura.
La microsegmentazione risponde portando il confine fino al singolo workload: ogni carico di lavoro
ha la sua politica, e ciò che non è esplicitamente permesso è negato.&lt;/p&gt;
&lt;h2 id=&#34;macro-contro-micro&#34;&gt;Macro contro micro
&lt;/h2&gt;&lt;pre class=&#34;mermaid&#34;&gt;
  flowchart TD
    subgraph MACRO[&amp;#34;Segmentazione classica (3 zone)&amp;#34;]
        direction LR
        A1[Web] &amp;lt;--&amp;gt; A2[App]
        A2 &amp;lt;--&amp;gt; A3[DB]
        A1 &amp;lt;--&amp;gt;|tutto libero&amp;lt;br/&amp;gt;dentro la zona| A3
    end
    subgraph MICRO[&amp;#34;Microsegmentazione&amp;#34;]
        direction LR
        B1[Web] --&amp;gt;|solo :8080| B2[App]
        B2 --&amp;gt;|solo :5432| B3[DB]
        B1 -.DB negato.-&amp;gt; B3
    end
&lt;/pre&gt;

&lt;p&gt;Nel modello classico, se il web server è compromesso raggiunge direttamente il DB. Nel modello
microsegmentato il web può parlare &lt;em&gt;solo&lt;/em&gt; all&amp;rsquo;app sulla porta applicativa, e solo l&amp;rsquo;app raggiunge
il DB: la rotta web→DB semplicemente non esiste. L&amp;rsquo;attaccante sul web server trova ogni altra
porta chiusa.&lt;/p&gt;
&lt;h2 id=&#34;lidentità-non-lindirizzo-ip&#34;&gt;L&amp;rsquo;identità, non l&amp;rsquo;indirizzo IP
&lt;/h2&gt;&lt;p&gt;La svolta della microsegmentazione è che le regole non si basano più sull&amp;rsquo;IP — che cambia, si
riusa, si falsifica — ma sull&amp;rsquo;&lt;strong&gt;identità&lt;/strong&gt; del workload: un&amp;rsquo;etichetta, un ruolo, un certificato.
Questo è anche il legame con il &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/zero-trust-architecture/&#34; &gt;modello Zero Trust&lt;/a&gt;:
la posizione in rete non conferisce fiducia, l&amp;rsquo;identità sì.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# Kubernetes NetworkPolicy: il DB accetta solo dall&amp;#39;app, solo sulla 5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;NetworkPolicy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;db-allow-app-only&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;podSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matchLabels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;role&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;database }&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ingress&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;from&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- &lt;span class=&#34;nt&#34;&gt;podSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;matchLabels&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;role&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;app } }&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;ports&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;- {&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;protocol: TCP, port&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;m&#34;&gt;5432&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;}&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Le righe evidenziate sono la regola: &lt;em&gt;solo&lt;/em&gt; i pod con etichetta &lt;code&gt;role: app&lt;/code&gt; possono raggiungere il
database, &lt;em&gt;solo&lt;/em&gt; sulla 5432. Gli IP dei pod cambiano a ogni riavvio; l&amp;rsquo;etichetta no. La politica
sopravvive alla volatilità dell&amp;rsquo;infrastruttura.&lt;/p&gt;
&lt;h2 id=&#34;default-deny-il-principio-che-regge-tutto&#34;&gt;Default deny: il principio che regge tutto
&lt;/h2&gt;&lt;p&gt;La microsegmentazione funziona solo se la posizione di partenza è &lt;strong&gt;nega tutto&lt;/strong&gt;. In Kubernetes,
una volta che un pod è selezionato da una policy di ingress, tutto ciò che non è esplicitamente
permesso è bloccato. Si parte chiudendo, poi si aprono le sole rotte necessarie — l&amp;rsquo;opposto del
modello &amp;ldquo;apri tutto, poi blocca le minacce note&amp;rdquo; dei &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/stateful-firewalls-nftables/&#34; &gt;firewall perimetrali&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-yaml&#34; data-lang=&#34;yaml&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# default deny: nessun ingresso a meno che un&amp;#39;altra policy lo permetta&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;apiVersion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;networking.k8s.io/v1&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;kind&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;NetworkPolicy&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;metadata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;l&#34;&gt;default-deny-ingress }&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;spec&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;podSelector&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;{}&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c&#34;&gt;# tutti i pod del namespace&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;policyTypes&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;l&#34;&gt;Ingress]&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;il-vero-costo-conoscere-i-flussi&#34;&gt;Il vero costo: conoscere i flussi
&lt;/h2&gt;&lt;p&gt;Scrivere le politiche è la parte facile. La parte difficile è &lt;strong&gt;sapere&lt;/strong&gt; quali flussi sono
legittimi: quale servizio parla con quale, su quale porta, in condizioni normali. Senza questa
mappa, il default deny spegne l&amp;rsquo;applicazione. Per questo la microsegmentazione inizia quasi sempre
con una fase di &lt;strong&gt;osservazione&lt;/strong&gt; (vedi &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/network-observability/&#34; &gt;network observability&lt;/a&gt;):
si raccolgono i flussi reali, si costruisce la mappa, poi si traduce in politiche. Strumenti basati
su &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/ebpf-network-security/&#34; &gt;eBPF&lt;/a&gt; come Cilium fanno proprio questo — osservano
e poi applicano.&lt;/p&gt;
&lt;h2 id=&#34;lab&#34;&gt;Lab
&lt;/h2&gt;&lt;p&gt;In un cluster di test (kind, minikube) con un CNI che supporti le NetworkPolicy (Calico, Cilium —
vedi &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/cni-plugins-calico-vs-flannel/&#34; &gt;CNI plugins&lt;/a&gt;):&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Distribuite tre pod: web, app, db con le relative etichette.&lt;/li&gt;
&lt;li&gt;Verificate che, senza policy, web raggiunge direttamente db (il problema).&lt;/li&gt;
&lt;li&gt;Applicate il &lt;code&gt;default-deny-ingress&lt;/code&gt;: tutto si blocca.&lt;/li&gt;
&lt;li&gt;Aggiungete le policy che aprono web→app e app→db: l&amp;rsquo;applicazione torna a funzionare, ma web→db
resta negato.&lt;/li&gt;
&lt;li&gt;Dimostrate il contenimento: da una shell nel pod web, provate a connettervi al db e osservate il
rifiuto.&lt;/li&gt;
&lt;/ol&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; se ho già firewall e VLAN tra le zone, la microsegmentazione non è solo complessità in più?&lt;/summary&gt;
&lt;p&gt;Dipende da cosa volete fermare. Firewall e VLAN fermano l&#39;attaccante &lt;em&gt;tra&lt;/em&gt; le zone, ma non
fanno nulla contro il movimento &lt;em&gt;dentro&lt;/em&gt; una zona — ed è lì che avviene la maggior parte dei
danni dopo una compromissione iniziale. Un ransomware che entra da una workstation di una VLAN uffici,
in un modello classico, raggiunge ogni altra macchina di quella VLAN senza incontrare un solo
controllo. La microsegmentazione è l&#39;unico modello che contiene questo: anche la macchina accanto è
&#34;fuori&#34; per default. Il costo è reale — serve conoscere i flussi e gestirne le politiche — e per questo
non si applica ovunque allo stesso livello: si concentra dove i dati valgono di più. Non sostituisce il
perimetro, lo completa partendo dall&#39;assunto che il perimetro verrà bucato.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;La microsegmentazione sposta il confine di sicurezza dalle poche zone di rete al singolo workload,
e lo fa legando le politiche all&amp;rsquo;identità invece che all&amp;rsquo;indirizzo. Il suo scopo preciso è
contenere il movimento laterale: trasformare una singola macchina compromessa in un vicolo cieco
invece che in un trampolino. Regge su un principio — default deny — e su un prerequisito — conoscere
i flussi reali. È la traduzione concreta, a livello di rete, del principio Zero Trust.&lt;/p&gt;
</description>
        </item>
        <item>
        <title>Firewall stateful con nftables</title>
        <link>https://www.matteobianchi.eu/p/stateful-firewalls-nftables/</link>
        <pubDate>Tue, 18 Aug 2026 09:00:00 +0200</pubDate>
        
        <guid>https://www.matteobianchi.eu/p/stateful-firewalls-nftables/</guid>
        <description>&lt;img src="https://www.matteobianchi.eu/p/stateful-firewalls-nftables/cover.png" alt="Featured image of post Firewall stateful con nftables" /&gt;&lt;h2 id=&#34;perché-conta&#34;&gt;Perché conta
&lt;/h2&gt;&lt;p&gt;Il &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/threat-modeling-networks/&#34; &gt;threat model&lt;/a&gt; ha prodotto regole come &amp;ldquo;dalla
DMZ nessuna connessione verso la LAN&amp;rdquo; (T5) e &amp;ldquo;la rete ospiti non raggiunge la LAN&amp;rdquo; (T1). Un
firewall è lo strumento che le mette in pratica. Ma un firewall scritto male è peggio di nessun
firewall: dà un falso senso di sicurezza. La differenza tra un firewall fragile e uno solido sta
in una parola: &lt;strong&gt;stato&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Su Linux lo strumento moderno è &lt;strong&gt;nftables&lt;/strong&gt;, che dal 2014 sostituisce iptables. Qui vediamo
perché lo stato cambia tutto e come scrivere un ruleset leggibile.&lt;/p&gt;
&lt;h2 id=&#34;stateless-contro-stateful&#34;&gt;Stateless contro stateful
&lt;/h2&gt;&lt;p&gt;Un firewall &lt;strong&gt;stateless&lt;/strong&gt; giudica ogni pacchetto da solo, senza memoria. Per permettere al PC
della LAN di navigare, deve consentire sia i pacchetti in uscita verso la porta 443, sia quelli
in ingresso dalla porta 443. Ma &amp;ldquo;permettere l&amp;rsquo;ingresso dalla 443&amp;rdquo; apre la porta a chiunque abbia
quella porta di origine: un attaccante la usa per entrare.&lt;/p&gt;
&lt;p&gt;Un firewall &lt;strong&gt;stateful&lt;/strong&gt; ricorda le connessioni aperte. Permette l&amp;rsquo;uscita, e lascia entrare
&lt;strong&gt;solo&lt;/strong&gt; le risposte che appartengono a una connessione che l&amp;rsquo;host ha iniziato. Non serve nessuna
regola di ritorno. Su Linux questa memoria è &lt;strong&gt;conntrack&lt;/strong&gt;, e ogni connessione attraversa stati
precisi:&lt;/p&gt;
&lt;pre class=&#34;mermaid&#34;&gt;
  stateDiagram-v2
    [*] --&amp;gt; NEW: primo pacchetto (SYN)
    NEW --&amp;gt; ESTABLISHED: risposta vista (SYN-ACK)
    ESTABLISHED --&amp;gt; ESTABLISHED: traffico nei due sensi
    ESTABLISHED --&amp;gt; [*]: chiusura / timeout
    NEW --&amp;gt; INVALID: pacchetto che non ha senso
    note right of ESTABLISHED
        RELATED: connessione nuova ma legata
        a una esistente (es. dati FTP, errori ICMP)
    end note
&lt;/pre&gt;

&lt;p&gt;La regola d&amp;rsquo;oro di ogni firewall stateful sta in una riga: &lt;strong&gt;accetta ciò che è &lt;code&gt;established&lt;/code&gt; o
&lt;code&gt;related&lt;/code&gt;, scarta ciò che è &lt;code&gt;invalid&lt;/code&gt;, e giudica con attenzione solo i pacchetti &lt;code&gt;new&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id=&#34;un-ruleset-nftables-commentato&#34;&gt;Un ruleset nftables commentato
&lt;/h2&gt;&lt;p&gt;Questo è il firewall di un host o di un gateway. nftables usa un unico file, con una sintassi più
leggibile di iptables.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14
&lt;/span&gt;&lt;span class=&#34;hl&#34;&gt;&lt;span class=&#34;lnt&#34;&gt;15
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;16
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;17
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;18
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;19
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;20
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;21
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;22
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;23
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;24
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;25
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;26
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;27
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;#!/usr/sbin/nft -f
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;flush ruleset
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;table inet filter {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chain input {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        type filter hook input priority 0; policy drop;   # default: scarta tutto
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ct state established,related accept                 # le risposte alle connessioni aperte
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ct state invalid drop                               # pacchetti incoerenti: via subito
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        iif lo accept                                       # il traffico di loopback è sempre ok
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ip protocol icmp icmp type echo-request limit rate 5/second accept
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        tcp dport 22 ct state new accept                    # SSH: solo pacchetti nuovi
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line hl&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chain forward {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        type filter hook forward priority 0; policy drop;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ct state established,related accept
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ct state invalid drop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        # DMZ (10.0.1.0/24) non deve raggiungere la LAN (10.0.10.0/24) -&amp;gt; minaccia T5
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ip saddr 10.0.1.0/24 ip daddr 10.0.10.0/24 drop
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    chain output {
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        type filter hook output priority 0; policy accept;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    }
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Le righe che contano:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;policy drop&lt;/code&gt; (riga 8 e la gemella nella catena forward): il default è &lt;strong&gt;negare&lt;/strong&gt;. Tutto ciò che
non è esplicitamente permesso viene scartato. È l&amp;rsquo;opposto di &amp;ldquo;apri e poi chiudi i buchi&amp;rdquo;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ct state established,related accept&lt;/code&gt; (riga 9): è la riga che rende il firewall stateful.
Le risposte passano senza regole di ritorno.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ct state invalid drop&lt;/code&gt; (riga 10): scarta pacchetti che non appartengono a nessuna connessione
valida, come certi scan.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tcp dport 22 ct state new accept&lt;/code&gt; (riga 15): SSH è permesso solo come &lt;strong&gt;nuova&lt;/strong&gt; connessione.
Nota che non serve nessuna regola per far tornare le risposte: le gestisce già la riga 9.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Si carica e si ispeziona così:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft -f firewall.nft        &lt;span class=&#34;c1&#34;&gt;# carica il ruleset&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nft list ruleset           &lt;span class=&#34;c1&#34;&gt;# lo mostra&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;conntrack -L               &lt;span class=&#34;c1&#34;&gt;# elenca le connessioni tracciate in tempo reale&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;lattacco-che-lo-stato-ferma&#34;&gt;L&amp;rsquo;attacco che lo stato ferma
&lt;/h2&gt;&lt;p&gt;Un classico scan &lt;code&gt;nmap -sA&lt;/code&gt; (ACK scan) invia pacchetti ACK senza una connessione sottostante, per
capire quali porte sono filtrate. Su un firewall stateless mal scritto, che accetta gli ACK
&amp;ldquo;perché sembrano risposte&amp;rdquo;, lo scan mappa la rete. Su quello sopra, quei pacchetti cadono in
&lt;code&gt;ct state invalid&lt;/code&gt; o non trovano una connessione &lt;code&gt;established&lt;/code&gt;, e vengono scartati. Lo scan non
ottiene informazioni.&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# dal nodo attacker, contro il gateway: lo scan non deve rivelare nulla&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;nmap -sA 10.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id=&#34;nftables-contro-iptables&#34;&gt;nftables contro iptables
&lt;/h2&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;iptables&lt;/th&gt;
&lt;th&gt;nftables&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Tabelle&lt;/td&gt;
&lt;td&gt;separate per IPv4/IPv6 (&lt;code&gt;iptables&lt;/code&gt;/&lt;code&gt;ip6tables&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;una sola (&lt;code&gt;inet&lt;/code&gt;) per entrambi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sintassi&lt;/td&gt;
&lt;td&gt;una regola per riga, verbosa&lt;/td&gt;
&lt;td&gt;insiemi, mappe, sintassi compatta&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Più condizioni&lt;/td&gt;
&lt;td&gt;più regole&lt;/td&gt;
&lt;td&gt;un&amp;rsquo;unica regola con &lt;code&gt;set&lt;/code&gt; e &lt;code&gt;map&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stato del progetto&lt;/td&gt;
&lt;td&gt;in manutenzione&lt;/td&gt;
&lt;td&gt;successore ufficiale&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Non c&amp;rsquo;è motivo di scrivere nuovi firewall in iptables nel 2026. Chi ha ruleset iptables esistenti
può convertirli con &lt;code&gt;iptables-translate&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id=&#34;lab&#34;&gt;Lab
&lt;/h2&gt;&lt;p&gt;Nel lab containerlab, sul nodo &lt;code&gt;gateway&lt;/code&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Caricate il ruleset con &lt;code&gt;nft -f firewall.nft&lt;/code&gt; e verificate &lt;code&gt;nft list ruleset&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Da &lt;code&gt;victim&lt;/code&gt;, aprite una connessione in uscita (&lt;code&gt;curl&lt;/code&gt; verso un servizio sul gateway) e guardate
&lt;code&gt;conntrack -L&lt;/code&gt; sul gateway: la connessione appare come &lt;code&gt;ESTABLISHED&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Da &lt;code&gt;attacker&lt;/code&gt;, provate &lt;code&gt;nmap -sA 10.0.0.1&lt;/code&gt; e poi &lt;code&gt;nmap -sS 10.0.0.1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Osservate quali pacchetti incrementano il contatore &lt;code&gt;invalid&lt;/code&gt; (&lt;code&gt;nft list ruleset&lt;/code&gt; mostra i
contatori se aggiungete &lt;code&gt;counter&lt;/code&gt; alle regole).&lt;/li&gt;
&lt;/ol&gt;


&lt;details&gt;
&lt;summary&gt;&lt;strong&gt;Domanda:&lt;/strong&gt; perché la catena output ha policy accept e non drop?&lt;/summary&gt;
&lt;p&gt;È una scelta, non un obbligo. Per un host singolo, filtrare anche l&#39;output è più sicuro (limita
cosa un processo compromesso può contattare), ma rende il ruleset molto più lungo e rischia di
rompere servizi legittimi. Per un firewall didattico si parte con output in accept e si filtra solo
input e forward. In un ambiente ad alta sicurezza si mette anche output in &lt;code&gt;policy drop&lt;/code&gt;
e si elencano le destinazioni permesse: è lo stesso principio Zero Trust del
&lt;a href=&#34;https://www.matteobianchi.eu/p/zero-trust-architecture/&#34;&gt;post dedicato&lt;/a&gt;, applicato al traffico in uscita.&lt;/p&gt;
&lt;/details&gt;


&lt;h2 id=&#34;conclusione&#34;&gt;Conclusione
&lt;/h2&gt;&lt;p&gt;Un firewall solido si regge su tre scelte: default &lt;code&gt;drop&lt;/code&gt;, stato con conntrack, e regole che
dicono &lt;em&gt;solo&lt;/em&gt; cosa è nuovo e permesso. Lo stato elimina intere categorie di errori — le regole di
ritorno — e con esse intere categorie di attacchi.&lt;/p&gt;
&lt;p&gt;Il firewall blocca ciò che riconosce come vietato. Ma cosa succede quando il traffico è permesso e
contiene comunque un attacco? Serve qualcosa che guardi &lt;em&gt;dentro&lt;/em&gt; i pacchetti. È il compito di un
IDS/IPS.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prossimo nella serie:&lt;/strong&gt; &lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/ids-ips-suricata/&#34; &gt;05 · IDS/IPS con Suricata&lt;/a&gt; ·
&lt;a class=&#34;link&#34; href=&#34;https://www.matteobianchi.eu/p/network-security-roadmap/&#34; &gt;Torna alla roadmap&lt;/a&gt;&lt;/p&gt;
</description>
        </item>
        
    </channel>
</rss>
