Il linguaggio Rust sta entrando in progetti dove un errore costa caro, come kernel, browser e infrastrutture cloud, e il motivo ti riguarda anche se non scrivi codice: una parte consistente delle vulnerabilità gravi nasce da errori nella gestione della memoria, e Rust è progettato per bloccare quegli errori prima che il programma venga eseguito.
Ho scritto questo articolo per due lettori. Se sviluppi, ti servono i concetti chiave (ownership, borrow checker, lifetime) con un esempio che compila davvero. Se guidi un'azienda e devi scegliere tecnologie o fornitori, qui trovi i dati verificati, le raccomandazioni delle agenzie di sicurezza e un metodo per decidere se e dove adottarlo.
Il problema: la memoria gestita a mano in C e C++
C e C++ lasciano al programmatore la gestione della memoria: chi scrive il codice decide quando allocare un'area, quando liberarla e quanto spazio leggere o scrivere. Funziona, ed è uno dei motivi per cui questi linguaggi sono veloci, ma basta una svista per lasciare nel tuo programma un difetto sfruttabile.
Gli errori tipici hanno nomi precisi, e ti conviene riconoscerli quando li leggi in un bollettino di sicurezza:
- buffer overflow: scrivi oltre la fine di un'area di memoria e sovrascrivi dati vicini;
- use after free: usi un puntatore dopo aver liberato la memoria a cui puntava;
- double free: liberi due volte la stessa area;
- data race: due thread modificano lo stesso dato senza coordinarsi.
Un attaccante può usare questi difetti per leggere dati riservati, mandare in crash il tuo servizio o eseguire codice. Non sono errori teorici: sono la causa principale delle vulnerabilità più gravi nei grandi progetti scritti in C e C++.
Il dato del 70%: cosa misura davvero
Il numero che circola più spesso è "70%". Se lo usi in una riunione o in un documento, citalo con precisione, perché le fonti misurano cose diverse.
Il Microsoft Security Response Center, in un post del luglio 2019, riporta che circa il 70% delle vulnerabilità a cui Microsoft assegna una CVE ogni anno riguarda la sicurezza della memoria. Il dato ti dice quindi qualcosa sulle vulnerabilità dei prodotti Microsoft che hanno ricevuto un identificativo pubblico, non su tutto il software.
Il progetto Chromium indica che circa il 70% dei suoi bug di sicurezza di gravità alta o critica è un problema di memory safety. L'analisi si basa su 912 bug di quella gravità, dal 2015, che riguardavano il canale Stable del browser.
Nessuna delle due fonti dice che "il 70% di tutte le vulnerabilità del mondo" dipende dalla memoria. Dicono una cosa più utile: in due basi di codice enormi, scritte soprattutto in C e C++, la maggioranza dei problemi gravi appartiene a una sola famiglia. Se elimini quella famiglia alla radice, riduci il rischio del tuo software in modo misurabile.
Garbage collector o ownership: due strade per la sicurezza
Rust non è l'unico linguaggio sicuro per la memoria. Java, C#, Go e Python lo sono già. Usano un garbage collector: un componente che durante l'esecuzione trova la memoria non più usata e la libera da solo. È comodo, ma ha un costo: memoria in più e pause che non controlli del tutto. Per un'applicazione gestionale va benissimo, mentre per un driver, un sistema embedded o un proxy che gestisce milioni di richieste, spesso no.
Rust sceglie un'altra strada: l'ownership. Ogni valore ha un solo proprietario. Quando il proprietario esce dal suo blocco di codice, la memoria viene liberata in automatico. Le regole sono controllate dal compilatore, non durante l'esecuzione, e il risultato è una gestione della memoria senza garbage collector e senza free() scritte a mano da te. La documentazione ufficiale sull'ownership lo spiega passo per passo.
Borrow checker e lifetime: le regole che il compilatore fa rispettare
Se ogni valore ha un solo proprietario, come lo usi in più punti del programma? Lo presti. Un prestito (borrow) è un riferimento al valore, senza cederne la proprietà. Il borrow checker è la parte del compilatore che verifica due regole:

Foto: kuszapro · Pixabay · Licenza dei contenuti Pixabay
- puoi avere molti riferimenti in sola lettura, oppure un solo riferimento che modifica il dato;
- un riferimento non può vivere più a lungo del valore a cui punta.
La seconda regola si esprime con i lifetime: annotazioni che descrivono quanto a lungo un riferimento resta valido. Nella maggior parte dei casi il compilatore li deduce da solo e tu li scrivi a mano solo quando il rapporto tra più riferimenti è ambiguo, come spiega il capitolo sui lifetime.
Ecco un esempio che ho compilato con rustc 1.95 e che puoi provare anche tu: una String viene prima prestata a una funzione, poi spostata (move) in un'altra variabile:
fn stampa(testo: &str) {
println!("{testo}");
}
fn main() {
let saluto = String::from("ciao");
stampa(&saluto); // prestito: saluto resta valido
let altro = saluto; // move: la proprietà passa ad altro
println!("{altro}");
// println!("{saluto}"); // errore E0382: valore usato dopo il move
}
Il programma stampa due volte "ciao". Se togli il commento dall'ultima riga, il compilatore si rifiuta di produrre l'eseguibile. Questo è un estratto del messaggio:
error[E0382]: borrow of moved value: `saluto`
--> src/main.rs:10:16
|
6 | let saluto = String::from("ciao");
| ------ move occurs because `saluto` has type `String`, which does not implement the `Copy` trait
7 | stampa(&saluto); // prestito: saluto resta valido
8 | let altro = saluto; // move: la proprietà passa ad altro
| ------ value moved here
9 | println!("{altro}");
10 | println!("{saluto}");
| ^^^^^^ value borrowed here after move
In C un errore simile, usare memoria che non ti appartiene più, compilerebbe senza problemi e potrebbe emergere mesi dopo in produzione. In Rust l'errore E0382 lo ferma sulla tua scrivania. È questo il cambio di prospettiva: una classe di bug passa dal "trovarla con i test" al "non può esistere nel codice compilato".
Prestazioni e concorrenza senza compromessi sulla sicurezza
Le zero-cost abstractions sono un principio di progetto: le astrazioni di alto livello, come iteratori e closure, non devono costare più del codice scritto a mano. Il libro ufficiale di Rust mostra che un ciclo con iteratori viene compilato in codice paragonabile a un ciclo scritto a basso livello. In pratica ti permette di scrivere codice leggibile senza pagare in velocità.
La fearless concurrency è l'altra conseguenza delle regole di ownership. Lo stesso controllo che impedisce di usare memoria liberata impedisce anche a due thread di modificare lo stesso dato senza protezione. Molti data race diventano errori di compilazione, come descrive il capitolo sulla concorrenza. Se il tuo servizio gestisce molte richieste in parallelo, è un vantaggio concreto.
Un limite va detto con chiarezza. Rust ha la parola chiave unsafe, che permette operazioni non verificate dal compilatore: serve per parlare con l'hardware o con librerie C. Le garanzie valgono per il codice sicuro; i blocchi unsafe vanno tenuti piccoli e revisionati con attenzione. Rust inoltre non ti protegge da errori di logica, injection o configurazioni sbagliate.
Cargo: dipendenze, test e build in un solo strumento
Cargo è lo strumento ufficiale che compila il progetto, scarica le librerie (crate), esegue i test e genera la documentazione. Con cargo new, cargo build e cargo test il tuo progetto ha una struttura standard fin dal primo giorno, e cargo clippy aggiunge controlli di qualità sul codice.
Dal punto di vista della sicurezza, Cargo semplifica molto ma non elimina il rischio delle dipendenze. Ogni crate di terze parti è codice che entra nel tuo prodotto. Il database RustSec raccoglie gli avvisi di sicurezza sulle librerie Rust e lo strumento cargo audit li confronta con le tue dipendenze. Il tema è lo stesso che ho trattato parlando di attacchi alla supply chain: la sicurezza della memoria non ti protegge da una libreria compromessa.
Dove si usa già il linguaggio Rust
Ecco qualche dato verificato, utile per spiegare al tuo team o ai tuoi soci che non parliamo di un esperimento accademico.
- Kernel Linux. Il kernel 6.1, rilasciato l'11 dicembre 2022, ha introdotto il supporto iniziale a Rust. Al Maintainers Summit del dicembre 2025 gli sviluppatori hanno concordato che Rust nel kernel non è più sperimentale. Il kernel resta scritto in gran parte in C: Rust affianca il C, soprattutto per driver e nuovi componenti, non lo sostituisce.
- Android. Google ha spostato lo sviluppo di nuove funzioni verso linguaggi sicuri per la memoria a partire dal 2019. Secondo il Google Security Blog, la quota di vulnerabilità di memoria in Android è scesa dal 76% del 2019 al 24% stimato per il 2024. Il dato 2024 è una proiezione sull'anno intero.
- Cloud. AWS ha scritto in Rust Firecracker, la tecnologia di virtualizzazione leggera che nel 2018 alimentava già AWS Lambda e AWS Fargate. Cloudflare ha costruito in Rust Pingora, il proxy HTTP che nel 2022 gestiva già quasi tutte le richieste verso i server di origine, al posto del precedente servizio basato su NGINX.
- WebAssembly. Rust può compilare verso WebAssembly, per eseguire nel browser moduli veloci accanto a JavaScript.
Anche gli sviluppatori lo apprezzano: nel sondaggio Stack Overflow 2025 Rust è il linguaggio più "admired" (72% di chi lo usa vuole continuare a farlo). Tieni presente che è un dato di gradimento, non di diffusione: Rust resta molto meno usato di JavaScript o Python.
Perché conta per chi decide: le raccomandazioni pubbliche
Se non scrivi codice, la domanda è un'altra: devo preoccuparmene? Le agenzie di sicurezza statunitensi hanno risposto in modo esplicito.
- Nel dicembre 2023 CISA, NSA e partner internazionali hanno pubblicato The Case for Memory Safe Roadmaps, che chiede ai produttori di software di pubblicare un piano per passare a linguaggi sicuri per la memoria.
- Il 26 febbraio 2024 l'Office of the National Cyber Director della Casa Bianca ha diffuso il rapporto Back to the Building Blocks, che invita a ridurre alla fonte intere classi di vulnerabilità adottando linguaggi memory-safe.
- Il 24 giugno 2025 NSA e CISA hanno pubblicato la scheda Memory Safe Languages: Reducing Vulnerabilities in Modern Software Development, rivolta in particolare a chi produce software per infrastrutture critiche.
Sono indicazioni, non leggi. Ma orientano gli acquisti pubblici e i requisiti dei grandi clienti. Se vendi software o lo fai sviluppare, prima o poi qualcuno ti chiederà come gestisci questo rischio.
Come valutare Rust nel tuo progetto, passo per passo
Riscrivere tutto in Rust è quasi sempre la scelta sbagliata, perché costa, introduce nuovi bug e ferma lo sviluppo del tuo prodotto. L'approccio che funziona è graduale, come quello descritto da Google per Android: il codice nuovo nei linguaggi sicuri, quello vecchio e stabile protetto e monitorato.
- Fai l'inventario. Elenca i componenti scritti in C o C++, anche dentro librerie e firmware di terze parti.
- Individua i punti esposti. Dai priorità a ciò che riceve dati dall'esterno: parser di file, gestione di protocolli di rete, decodifica di immagini o documenti.
- Guarda lo storico. Controlla quali componenti hanno avuto più vulnerabilità o crash. Lì un linguaggio sicuro rende di più.
- Scegli un pilota piccolo. Un modulo isolato, con interfacce chiare, che puoi riscrivere e confrontare con l'originale.
- Integra invece di sostituire. Rust dialoga con il C tramite FFI (Foreign Function Interface): il nuovo modulo può convivere con il resto del sistema.
- Misura. Confronta prestazioni, crash e tempi di sviluppo prima e dopo. Decidi il passo successivo sui dati.
- Forma il team. Il borrow checker richiede settimane di pratica. Metti in conto la curva di apprendimento nel piano.
Se il tuo software è un gestionale in Java o un sito in PHP, il problema della memoria è già gestito dal linguaggio. In quel caso la priorità sono altri rischi, come quelli descritti nella lezione su injection, XSS e accessi ai dati.
Checklist ed errori da evitare
Usa questa lista prima di decidere e rispondi per il tuo software:
- So quali componenti del mio software sono in C o C++.
- So quali di questi elaborano dati non fidati.
- Ho un pilota con perimetro e metriche definite.
- Le dipendenze Rust sono verificate con
cargo audit. - I blocchi
unsafesono pochi, motivati e revisionati. - Il team ha tempo per imparare, non solo per consegnare.
Gli errori più comuni che ti consiglio di evitare:
- Riscrivere tutto subito. Il rischio di regressioni supera il beneficio.
- Considerare Rust una garanzia totale. Protegge la memoria, non la logica, l'autenticazione o la configurazione.
- Abusare di
unsafeper aggirare il compilatore quando è scomodo. - Ignorare le dipendenze, come se un crate fosse sicuro solo perché scritto in Rust.
- Scegliere per moda. Se il collo di bottiglia è altrove, Rust non lo risolve.
Consigli pratici per iniziare
Se sei uno sviluppatore, installa la toolchain ufficiale con rustup e segui le risorse della pagina Learn di rust-lang.org. Parti da un piccolo strumento a riga di comando che conosci bene, per esempio un parser di file di log. Lascia che il compilatore ti corregga: i suoi messaggi spiegano il problema e spesso suggeriscono la soluzione, come hai visto con E0382.
Se sei un titolare, fai tre domande al tuo fornitore: in quali linguaggi è scritto il software che ci consegni? Come gestite le vulnerabilità delle dipendenze? Avete un piano per i componenti più esposti? Le risposte ti dicono molto sulla maturità di chi lavora per te. Se il tuo software ha anni di stratificazioni, un'analisi del debito tecnico è il punto di partenza per capire dove intervenire.
Se nel tuo software gestisci vulnerabilità già note, collegale al loro impatto reale prima di pianificare riscritture: il metodo è descritto nella lezione su CVE, CVSS e priorità.
Domande frequenti
Rust è nato nei laboratori di Mozilla?
Non proprio, ed è un dettaglio che ti conviene correggere se lo trovi in una presentazione. Secondo MIT Technology Review, Rust è nato nel 2006 come progetto personale di Graydon Hoare, allora programmatore di Mozilla. Mozilla ha iniziato a sponsorizzarlo ufficialmente nel 2009. La versione Rust 1.0 è uscita il 15 maggio 2015.
Rust è il secondo linguaggio ufficiale del kernel Linux?
La formula è imprecisa e ti consiglio di evitarla. Il kernel supporta Rust dalla versione 6.1 e dal dicembre 2025 il supporto non è più considerato sperimentale. Il C resta però il linguaggio della grande maggioranza del codice; Rust viene usato accanto al C, soprattutto per driver e nuovi sottosistemi.
Rust rende il mio software immune agli attacchi?
No. Rust elimina gran parte degli errori di memoria nel codice sicuro, ma nel tuo software restano possibili errori di logica, injection, problemi di autenticazione, configurazioni sbagliate e dipendenze compromesse. Un penetration test resta necessario anche su software scritto in Rust.
Devo riscrivere il mio gestionale in Rust?
Quasi certamente no. Se il tuo gestionale è scritto in un linguaggio con garbage collector, come Java o C#, è già sicuro per la memoria. Rust ha senso dove servono prestazioni da C senza i rischi del C: componenti di sistema, rete, elaborazione di dati non fidati.
Le mie considerazioni
Da ethical hacker, gli errori di memoria sono tra i difetti che mi interessano di più quando analizzo un componente scritto in C o C++. Sono difficili da trovare con una revisione a occhio e possono avere un impatto enorme. Per questo considero Rust una delle novità più serie degli ultimi anni nella sicurezza del software: non aggiunge un controllo in più, toglie una categoria di bug alla radice.
Da sviluppatore, però, diffido delle riscritture fatte per entusiasmo. Il codice vecchio che funziona contiene anni di correzioni, e riscriverlo significa rischiare di perderle. Al tuo posto partirei dalla mappa: dove arrivano dati non fidati, in quali componenti, in quale linguaggio. Poi sceglierei un solo modulo esposto come pilota e misurerei il risultato.
Se compri software, inizia a chiedere ai fornitori un piano sulla sicurezza della memoria, come raccomandano CISA e NSA. Se lo sviluppi, metti Rust nella lista delle opzioni per il prossimo componente critico, non per tutto il resto. Se vuoi capire da dove partire con il tuo codice, guarda come lavoro su debugging, code review e audit del software e chiedimi una prima analisi.






