“Controllare che qualcuno abbia un biglietto, ma non controllare mai che sia il biglietto per questo posto.”
L'autenticazione non è l'autorizzazione
Dietro "auth" si nascondono due domande diverse. L'autenticazione chiede chi sei, dimostrato da un login. L'autorizzazione chiede cosa puoi toccare, deciso per richiesta, per risorsa. Sono indipendenti: essere loggato (autenticato) non dice nulla sul fatto che tu possa leggere l'ordine n. 124 (autorizzazione). Gli strumenti IA riescono benissimo nella prima perché è visibile e richiesta nei prompt. Mancano la seconda perché, con un solo utente di test che possiede tutto, non si presenta mai.
Il risultato è un'app dove il login è solido e, una volta dentro, puoi raggiungere i dati di tutti. La porta d'ingresso ha una buona serratura; nessuna delle porte interne ne ha una.
Il bug che avrai davvero: IDOR
Insecure Direct Object Reference è il nome poco glamour del difetto più probabile nella tua app. Il pattern: una risorsa è indirizzata da un id, e il server la restituisce a chiunque sia autenticato, senza controllare la proprietà. La tua UI ti collega solo ai tuoi record, quindi sembra tutto a posto, ma l'id nell'URL o nella chiamata API è solo un numero, e cambiandolo ottieni quello di qualcun altro.
possiedi l'ordine 123
GET /api/orders/123 → 200 { il tuo ordine } ✓ corretto
GET /api/orders/124 → 200 { di qualcun altro } ✗ IDOR: nessun controllo di proprietà
^ l'unica cosa che hai cambiato è un numeroÈ banale da trovare e banale da sfruttare: incrementa un id, leggi la fattura di uno sconosciuto. Ed è ovunque nelle app costruite con l'IA, perché l'endpoint generato recupera il record per id e lo restituisce; la riga "questo utente ne è il proprietario?" è la protezione invisibile che nessuno ha chiesto.
L'auth deriva man mano che fai prompting
Un fallimento più sottile: una protezione aggiunta in un prompt sparisce in uno successivo, non correlato. Chiedi allo strumento di "aggiungere un filtro a questo endpoint", lui riscrive l'handler, e il controllo di proprietà che c'era è silenziosamente sparito, perché il modello ha rigenerato la funzione attorno alla nuova richiesta e non ha portato avanti il vecchio vincolo. L'endpoint restituisce ancora dati, la demo funziona ancora, e il buco si è riaperto senza lasciare traccia.
Per questo la sicurezza nelle app costruite con l'IA non può essere un passaggio una tantum. I controlli decadono ogni volta che rigeneri codice attorno a loro. Si ri-verifica dopo le modifiche, che è esattamente lo scopo della checklist del capitolo 6.
La regola: controlla sul server, ogni volta
Ogni difesa qui si riduce a una disciplina: il server decide, a ogni richiesta, usando valori che il client non può falsificare:
- Autentica ogni richiesta protetta lato server; non dedurre mai l'identità da qualcosa che il client ha inviato.
- Autorizza per risorsa: QUESTO utente autenticato possiede (o ha un ruolo che gli concede) QUESTA riga specifica? Non solo "è loggato".
- Non fidarti mai di uno user_id, di un ruolo o di un flag is_admin forniti dal client; deriva identità e permessi dalla sessione verificata.
- Nega per impostazione predefinita: se nessuna regola concede esplicitamente l'accesso, rifiuta. Preferisci restituire 404 invece di 403, così non confermi nemmeno che la risorsa esiste.
È lo stesso principio della Row-Level Security del capitolo 2, applicato al livello applicativo invece che al database. Anzi, i due si rinforzano a vicenda: la RLS intercetta ciò che un controllo applicativo mancato lascia passare, e viceversa. Difesa in profondità significa volerli entrambi.
Una riga per ciascuno
- Autenticazione (chi sei) e autorizzazione (cosa puoi toccare) sono cose diverse; l'IA costruisce la prima, salta la seconda.
- L'IDOR, restituire una risorsa per id senza controllare la proprietà, è il difetto grave più probabile in un'app costruita con l'IA.
- I controlli di autorizzazione derivano: rigenerare codice attorno a una protezione la fa cadere in silenzio, quindi la sicurezza va ri-verificata dopo le modifiche.
- La regola: il server decide per risorsa, a ogni richiesta, con un'identità verificata: negare per impostazione predefinita, mai fidarsi di id inviati dal client.
Dove andare ora