17.333.335.124.315 righe. È la stima, ricavata dai metadati, dei dati raggiungibili attraverso Titan, un servizio di analytics interno di Microsoft, secondo il resoconto pubblicato il 25 settembre 2026 da Faav, un ricercatore di 16 anni. L’interfaccia web di Titan mostrava a chiunque una pagina “VPN REQUIRED”. L’API no: stava su un host Azure raggiungibile da internet, e accettava token di cui non verificava mai la firma. Con un token costruito a mano e il nome utente admin, Faav eseguiva query SQL come amministratore.

Il caso è enorme, il meccanismo è banale, ed è lo stesso che si trova in piccolo su tanti siti di PMI: un endpoint raggiungibile da fuori, protetto da un controllo che sembra completo e non lo è. La domanda che pone è una scelta di progetto concreta per chiunque esponga un’API, anche solo una route REST di WordPress: ti fidi del perimetro o verifichi ogni richiesta?

Il criterio: cosa resta in piedi quando cade uno strato

Ogni difesa prima o poi cede in un punto: una regola firewall dimenticata, un sottodominio di staging, una route in più. Confronto le due strade su un solo criterio, declinato in tre domande: quanto costa metterle in piedi, cosa succede quando lo strato principale si rompe, e chi se ne accorge.

Opzione A: il perimetro

Perimetro vuol dire che la protezione sta attorno al servizio, non dentro: VPN, allowlist di IP, URL non linkati, pannelli raggiungibili solo dalla rete dell’ufficio. Il servizio, una volta dentro, si fida di chi arriva.

  • Pro: si configura in un pomeriggio, non richiede di toccare il codice dell’applicazione e blocca il rumore di fondo, cioè scanner e bot generici.
  • Contro: protegge solo la strada che conosci. Titan era chiuso sul frontend, ma il bot di Faav, Antares, ha trovato l’API cercando tra i sottodomini, e la documentazione Swagger pubblica elencava le quattro route disponibili: tre dichiaravano l’autenticazione, l’eccezione era /v2/Query, proprio quella che accettava SQL grezzo. Le 56 definizioni di tabella sono arrivate dalla configurazione archiviata nella Wayback Machine nel 2023.
  • Quando si rompe: tutto quello che sta dietro è esposto in un colpo, e di solito nessuno se ne accorge finché non lo segnala qualcun altro.

Opzione B: verifica a ogni richiesta

Qui ogni chiamata dimostra chi è e cosa può fare, da ovunque arrivi: un token firmato di cui il server verifica la firma con una chiave nota e un algoritmo fissato, poi un controllo dei permessi sulla singola operazione.

  • Pro: un endpoint trovato per caso resta inutile senza credenziali valide. Il danno di un token rubato si limita ai permessi di quel token.
  • Contro: va fatta su ogni route, e un solo passaggio saltato annulla il resto. Titan verificava tenant, audience, applicazione e utente, cioè il contenuto del token, e saltava la firma. Faav lo descrive come un hotel dove ogni porta ha il lettore di badge ma qualsiasi badge apre qualsiasi stanza.
  • Quando si rompe: se il difetto è in una route cade quella; se è nella funzione di verifica condivisa, cade tutto. Per questo la verifica si testa, non si presume.

Faav ha mandato un JWT con intestazione "alg": "none" e la terza parte vuota, e il server l’ha accettato. È un attacco noto da anni: la RFC 8725, le buone pratiche IETF sui JWT, lo cita tra i primi e chiede alle librerie di non accettare token none se il chiamante non lo richiede esplicitamente. Usare una libreria con l’algoritmo fissato, invece di scrivere la verifica a mano, è il modo più semplice per non ricadere in quel caso.

Dove si rompe su un sito WordPress

La versione WordPress dello stesso errore ha un nome preciso: permission_callback. Una route REST registrata senza questo parametro è pubblica. Il core, dalla 5.5, emette un avviso _doing_it_wrong proprio per questo, e il post del team core ammette che il caso “è successo più volte in produzione, con risultati che possono essere catastrofici”. Per le route volutamente pubbliche il manuale REST indica __return_true: così la scelta è scritta nel codice e chi legge sa che è voluta.

I tre punti dove lo vedo cedere più spesso sono sempre gli stessi. Il primo è lo snippet in functions.php che registra un endpoint per un’integrazione, scritto in fretta e senza controllo dei permessi. Il secondo è lo staging su sottodominio, “protetto” da un URL che nessuno conosce, con utenti e ordini copiati dalla produzione. Il terzo sono i plugin di autenticazione JWT configurati e mai testati con un token alterato. Ho già scritto di come la REST API esponga file che si credevano privati, e sulla gestione delle credenziali date a terzi c’è il pezzo su come revocare gli accessi esterni.

Costi e manutenzione per una PMI

Sul costo iniziale vince il perimetro: una regola nel firewall dell’hosting o una protezione con password a livello server costa minuti. La verifica per richiesta costa di più solo se la si scrive da zero. Su WordPress la parte pesante esiste già: current_user_can() nel permission_callback, le Application Password del core per le integrazioni, una libreria JWT matura se serve davvero un token.

Sulla manutenzione il rapporto si inverte. Il perimetro chiede di sapere in ogni momento quali host, sottodomini e route esistono, cioè proprio l’informazione che nelle PMI manca. La verifica per richiesta chiede una regola sola, da applicare a ogni route nuova, e si controlla con un test: token assente, token scaduto, token con firma alterata, utente senza permessi. Quattro chiamate che devono restituire tutte errore.

La mia scelta: verifica prima, perimetro come secondo strato

Il perimetro rallenta chi cerca, non decide chi entra. Serve, e su wp-admin o su un pannello di analytics lo tengo volentieri, ma come secondo strato. Se è l’unico, la sicurezza dipende dal fatto che nessuno trovi l’indirizzo giusto, e il caso Titan mostra che oggi a cercarlo è un bot che per dieci giorni ripete i tentativi senza stancarsi. Faav scrive che ad Antares mancava solo l’intuizione su admin: la costanza nella ricerca ce l’aveva già tutta.

Per chi costruisce integrazioni, automazioni o piccoli backend per clienti la regola che uso è secca: nessuna route senza un controllo esplicito dei permessi, nessun token verificato a mano, e ogni endpoint trattato come se fosse già stato trovato. Ne avevo parlato anche per Supabase e le policy RLS: anche lì il controllo sta sul dato, non sulla strada per arrivarci.

Cosa fare questa settimana

  1. Cerca register_rest_route nel tema e nei plugin custom e verifica che ogni chiamata abbia un permission_callback reale o un __return_true voluto.
  2. Elenca i sottodomini del sito, inclusi staging e vecchi ambienti di test, e spegni quelli che non servono.
  3. Se usi JWT, manda un token con la firma alterata e uno con alg impostato a none: devono essere rifiutati entrambi.
  4. Controlla che la documentazione pubblica delle API, se esiste, non elenchi route interne.

Faav ha segnalato il problema a Microsoft il 5 settembre, l’endpoint è stato chiuso il 9 e il 17 è arrivata una ricompensa di 5.000 dollari. Precisa che l’impatto descritto è ipotetico, che non ha toccato dati dei clienti e che Microsoft ha avuto il controllo editoriale sul post.

Fonti