Salvatore Vivolo
Torna al Blog
9 min di lettura

Dalla safety industriale alla sicurezza del software: due settimane di revisione di IkigaiApp con l'AI

Come un incidente dell'hosting ha avviato una revisione di sicurezza e privacy: controllo degli accessi, cifratura, autenticazione a due fattori e un metodo di lavoro con l'AI sotto responsabilità umana.

CybersecurityAIPrivacy

Lavoro da circa vent'anni nell'automazione industriale. In quel mondo una macchina si progetta sicura: prima si analizzano i rischi, poi si progettano protezioni, interblocchi e procedure, e si dimostra che funzionano. La sicurezza non si aggiunge dopo.

Safety industriale e cybersecurity affrontano rischi diversi, ma il metodo si può trasferire: rendere espliciti i rischi, progettare i controlli, verificarli. Nell'ottobre 2026 l'ho applicato a IkigaiApp, un mio progetto personale. Questa è la storia di due settimane dedicate a rivedere sicurezza e privacy dell'app: controlli da correggere, protezioni da verificare, decisioni da documentare. L'AI è stata lo strumento; le decisioni sono rimaste mie. Non tutti i controlli descritti sono nati in quelle due settimane: la revisione ha riguardato anche quelli che c'erano già.

L'app e la scintilla

IkigaiApp è una web app di autovalutazione basata sull'idea giapponese di ikigai: un questionario, un profilo personale, una descrizione del risultato scritta con l'AI e alcuni strumenti personali come diario e flashcard. Si sono iscritte circa 170 persone. Gira su servizi gestiti: una piattaforma edge per il sito, una piattaforma container nell'UE per l'API, un database gestito nell'UE.

Il 21 ottobre 2026 Railway, il fornitore che uso per l'API, ha comunicato un incidente: un soggetto non autorizzato poteva aver avuto accesso alle variabili d'ambiente cifrate dei clienti e, per alcune, al loro contenuto decifrato. È lì che vivono i segreti: le password del database, le chiavi che firmano le sessioni, le chiavi che proteggono i dati cifrati. Nella prima comunicazione i clienti coinvolti non erano ancora stati tutti identificati.

Ho ipotizzato il peggio. Ho rigenerato ogni segreto, compresa la chiave principale che protegge le chiavi di cifratura del database. Ho controllato i log disponibili di ogni servizio dall'inizio della finestra di esposizione, senza trovare segni di abuso. Ho attivato l'autenticazione a due fattori su ogni account dei fornitori e ho documentato l'incidente nel registro delle violazioni, con la valutazione del rischio e i motivi per cui, sulla base degli elementi disponibili, non era necessario notificarlo all'autorità.

Poteva finire lì. Invece è diventato l'inizio di una revisione completa.

Passo 1: chi vede cosa

L'esercizio più utile è stato anche il meno spettacolare: esaminare ogni route delle API, 283 in tutto, con tre domande. Chi può chiamarla? Di chi sono i dati che tocca? Cosa restituisce?

Sono emersi 14 problemi e 7 punti da approfondire. Alcuni erano sottili: un controllo che doveva rispondere a "questo utente è amministratore?" risultava sempre vero, perché una funzione veniva citata invece che chiamata. Altri erano classici: cambiando un ID nella richiesta si potevano vedere i dati di qualcun altro. Sono stati corretti tutti.

Ogni correzione è arrivata con un test che fallisce sul codice vecchio e passa su quello nuovo. Conta più di quanto sembri: un test passato da rosso a verde è una prova su quel caso, e impedisce che il difetto torni. Non dice che non ce ne siano altri, ed è per questo che la revisione è partita da tutte le route e non solo da quelle sospette.

La stessa revisione ha chiuso perdite più silenziose:

  • le risposte che riguardano altri utenti contengono solo un ID e un nome visualizzato;
  • l'app non rivela più se un indirizzo email ha un account;
  • i limiti di richieste rallentano chi prova ad automatizzare i tentativi.

Passo 2: proteggere i dati anche nel database

I dati personali (email, nome, nickname) e ciò che gli utenti scrivono nei loro strumenti personali (diario, to-do, Piccole Ancore, flashcard) vengono cifrati dall'applicazione prima di arrivare al database, con AES-256-GCM. Le chiavi seguono uno schema a busta: le chiavi dei dati sono cifrate da una chiave principale che non sta mai nel database. Ogni chiave ha una versione, così si può sostituire senza fermare il servizio. La chiave principale è già stata ruotata; la rotazione delle chiavi dei dati è uno dei prossimi passi.

I campi cifrati sono difficili da cercare, quindi accanto ad alcuni l'app salva un blind index: un hash con chiave del valore normalizzato. Permette di trovare un utente dall'email o di garantire nickname unici senza decifrare nulla e senza conservare il valore in chiaro. Non rende però il dato anonimo: due valori uguali producono lo stesso indice. Per questo l'indice va protetto insieme alle sue chiavi.

I cookie di sessione sono HttpOnly, Secure e SameSite: gli script della pagina non possono leggerli, viaggiano solo su connessioni cifrate e il browser non li allega alle richieste partite da altri siti. I link che agiscono senza login sono firmati e scadono. In produzione il server rifiuta di partire se manca un segreto obbligatorio: un'impostazione dimenticata non può ripiegare in silenzio su un valore debole.

Passo 3: un secondo fattore per le chiavi del regno

L'account amministratore ha privilegi elevati, quindi ora richiede l'autenticazione a due fattori. Ho scelto TOTP, lo standard aperto (RFC 6238) usato da Google Authenticator, Authy, Microsoft Authenticator e Apple Passwords.

È implementato con la crittografia standard della piattaforma e verificato sugli esempi ufficiali della specifica. I codici non sono riutilizzabili. I codici di recupero sono salvati solo come hash lenti. Esiste una procedura d'emergenza per il telefono smarrito: può eseguirla solo il titolare e viene registrata.

Passo 4: la privacy come vincolo di progetto

Alcune scelte di privacy costano qualcosa, ed è proprio questo il punto.

  • Ho rinunciato alle statistiche legate all'account. Le statistiche d'uso non registrano più l'ID utente né l'indirizzo IP: vedo quali pagine si usano, non chi le usa. Resta un solo cookie di prima parte: contiene un valore casuale, raggruppa le pagine di una stessa visita e dura 30 minuti. Le statistiche restano nel nostro database, si usano solo in forma aggregata e non vengono incrociate con altri dati né condivise. Ho valutato questa configurazione sulle linee guida del Garante: a queste condizioni il cookie si può trattare come tecnico, e per questo l'app non mostra un banner di consenso.
  • I dati scadono da soli. Statistiche dopo 13 mesi, dati tecnici dopo 90 giorni, registri dell'uso dell'AI dopo 12 mesi, log di sicurezza entro un anno. La scadenza la applica il database. Le copie di backup cifrate seguono un calendario proprio: vengono sostituite entro 6 mesi.
  • Cancellare l'account cancella i dati collegati. Un test riempie ogni collezione dell'app con dati di un utente, cancella l'account e verifica che non resti nulla. Sono stati ripuliti anche i record rimasti da account cancellati in passato. Restano solo i log di sicurezza fino alla loro scadenza e i backup fino alla sostituzione, come dice l'informativa.
  • Meno dati nei log. Segreti e indirizzi email vengono oscurati. Dove serve un riferimento uso ID e hash con chiave: sono dati pseudonimi, non anonimi, e per questo hanno una scadenza.
  • Niente interruttori finti. Sono stati tolti i consensi che non facevano nulla. Non uso i dati dell'app per marketing, non li vendo e non ci addestro modelli. Cosa ricevono i fornitori, compreso quello dell'AI, è scritto nell'informativa; il fornitore AI non usa questi dati per addestrare i suoi modelli.
  • L'informativa parte dal funzionamento reale. Ho riscritto le pagine legali pubbliche confrontandole con il codice e con i servizi usati, non partendo da un modello. Quando il codice cambia, l'informativa cambia con lui.

Passo 5: l'AI dentro il prodotto

L'app usa l'AI per scrivere il profilo narrativo, generare flashcard e tradurre i messaggi dell'amministratore. Ogni funzione riceve solo ciò che le serve. Il profilo, per esempio, riceve categorie derivate e mai un nome, un'email o una risposta libera. I contenuti generati sono etichettati "Generato con AI", per rendere visibile il ruolo dell'AI. La ricerca di profili simili è deterministica e spiegabile, non machine learning.

Il metodo: AI per la velocità, revisione umana per il giudizio

La maggior parte di questo codice non l'ho scritta a mano. Ho lavorato con due assistenti AI: uno ha analizzato il codice, scritto le specifiche e rivisto ogni modifica; l'altro le ha implementate su branch separati. Ogni decisione, ogni unione e ogni operazione in produzione l'ho fatta io.

Tre pratiche hanno fatto la differenza:

  1. Regole nel repository. Un file dice agli agenti cosa non devono mai fare: mettere segreti nel codice o nei log, indebolire un controllo di sicurezza, cambiare un comportamento senza test.
  2. Prove, non rassicurazioni. Ogni lotto si è chiuso con un report che confronta l'intera suite di test con il ramo principale test per test, non solo i totali.
  3. Modifiche in produzione in due tempi. Ogni modifica ai dati è uno script che prima fa una prova e stampa solo conteggi. L'esecuzione vera arriva dopo aver guardato i numeri, e dopo un backup cifrato nuovo.

La revisione delle modifiche ha trovato ciò che i test non vedevano. Una modifica superava tutti i suoi test, ma avrebbe cercato i dati da eliminare in tre collezioni con nomi sbagliati, lasciandoli nel database. I test usavano gli stessi nomi sbagliati. È emerso leggendo il diff, prima della produzione, e la correzione ha fatto derivare quei nomi dai modelli dei dati. Un'altra volta, semplicemente verificando che un backup si potesse decifrare, è venuto fuori che lo script mescolava un ritorno a capo nella chiave di cifratura. Entrambi sono stati corretti prima di fare danni. La lezione: un secondo assistente AI aiuta, ma non è una verifica indipendente. L'ultima lettura deve restare umana.

A che punto è, onestamente

Oggi so cosa è protetto, come lo verifico e cosa manca. Ogni correzione ha un test, ogni decisione ha un documento. Non ho fatto una valutazione esterna, e questa revisione non la sostituisce.

Non è finita. I prossimi passi:

  • aggiornamenti automatici delle dipendenze con integrazione continua;
  • tutta la suite di test verde e bloccante per ogni modifica;
  • rotazione delle chiavi di cifratura dei dati;
  • backup automatici cifrati;
  • avvisi automatici sulle anomalie;
  • passkey e, un giorno, un test di penetrazione esterno.

Cosa direi a chi inizia un progetto

  1. Verifica il controllo degli accessi route per route, prima di aggiungere funzioni.
  2. Cifra i campi sensibili nell'applicazione e prevedi la rotazione delle chiavi fin dal primo giorno.
  3. Raccogli meno dati: ciò che non conservi non va protetto né giustificato. Per ciò che resta, decidi scopo e scadenza.
  4. Fai in modo che l'informativa descriva il codice, e mantienili allineati.
  5. Usa l'AI per la velocità e le persone per il giudizio. Chiedi prove, non rassicurazioni.
  6. Per ogni modifica ai dati in produzione: backup, prova, revisione, esecuzione, verifica.

La safety by design funziona anche per il software. Gli strumenti sono nuovi; la disciplina no.

Il caso di studio tecnico completo, aggiornato a ogni passo, è qui: Caso di studio su sicurezza e privacy di IkigaiApp.

Se hai affrontato una revisione simile, o vuoi confrontarti su questo metodo, scrivimi.

Condividi l’articolo

LinkedInE-mail