Ogni applicazione moderna è due cose sovrapposte: un’interfaccia che le persone vedono e un insieme di interfacce di programmazione che scambiano dati dietro le quinte. Le seconde servono l’applicazione mobile, il portale dei clienti, le integrazioni con i fornitori, i sistemi delle controparti. Sono la parte che regge il funzionamento, ed è anche la parte che nella maggior parte delle verifiche di sicurezza non viene guardata.

Non per disattenzione. Un’interfaccia di programmazione non si esplora navigando, non compare in nessuna mappa del sito e spesso non risulta da nessun inventario aziendale. Chi verifica la sicurezza di un’applicazione partendo da ciò che è raggiungibile con un browser trova la facciata e lascia intatto tutto il resto.

  1. Perché un’API è diversa da una pagina web
  2. Il problema dell’inventario
  3. I difetti che ricorrono più spesso
  4. Perché gli strumenti automatici non bastano
  5. Chi possiede l’API: la parte organizzativa
Schermata di un'applicazione e ramificazione degli endpoint sottostanti

Perché un’API è diversa da una pagina web

Su una pagina web l’interfaccia grafica funziona anche come vincolo: mostra tre campi, quindi l’utente compila tre campi. È un vincolo debole — chiunque può aggirarlo — ma nella pratica orienta il comportamento della maggior parte delle persone.

Su un’interfaccia di programmazione quel vincolo non esiste, perché non c’è nessuna grafica a mediare. Il client dichiara cosa chiede e il servizio risponde, e il client non è necessariamente quello che avete scritto voi. Chiunque può inviare le stesse richieste con parametri diversi, in ordine diverso, con valori che la vostra applicazione mobile non produrrebbe mai. La superficie di attacco non è ciò che l’interfaccia consente di fare: è tutto ciò che il servizio accetta di eseguire.

C’è poi una differenza di visibilità che lavora contro di voi. Le pagine di un sito sono collegate tra loro da link, e questo permette di scoprirle percorrendole. Gli endpoint di un’API non sono collegati a nulla: esistono e rispondono, ma non si arriva a loro seguendo un percorso. Per conoscerli serve la documentazione, il traffico osservato, oppure il codice del client — e chi vuole attaccarvi il client lo ha, perché lo avete distribuito voi.

Il problema dell’inventario

Prima di qualsiasi considerazione tecnica viene una domanda banale a cui poche organizzazioni sanno rispondere: quante interfacce esposte avete, e dove. Nella pratica l’elenco che risulta dai documenti è sistematicamente più corto di quello reale, e le differenze si concentrano in tre categorie.

Ci sono le interfacce non documentate, nate per una necessità puntuale e mai censite. Ci sono le versioni precedenti rimaste attive perché qualche client vecchio le usava ancora, e che quasi mai ricevono le correzioni applicate alla versione corrente. E ci sono le interfacce di servizi dismessi, il cui applicativo è stato sostituito ma il cui endpoint continua a rispondere perché nessuno ha spento nulla.

Il punto è che una vulnerabilità su un’interfaccia che non sapete di avere non comparirà in nessuna delle vostre verifiche, ma sarà comunque raggiungibile da chi la cerca. È lo stesso meccanismo che rende difficile la gestione delle dipendenze di cui abbiamo parlato a proposito delle patch delle applicazioni web: non si aggiorna e non si verifica ciò che non è nell’inventario.

I difetti che ricorrono più spesso

Le famiglie di vulnerabilità che si trovano sulle interfacce di programmazione sono poche e straordinariamente costanti. La classificazione OWASP dedicata alle API le ordina in modo sistematico, e le prime posizioni riflettono quello che emerge nella pratica.

  1. Autorizzazione a livello di oggetto. Il servizio verifica che chi chiede sia autenticato, ma non che l’oggetto richiesto gli appartenga. È il difetto più diffuso e il più semplice: l’identificativo di una risorsa viene sostituito con un altro, e il servizio restituisce il dato di un altro cliente. Nessun errore di codice, solo un controllo mancante.
  2. Autorizzazione a livello di funzione, dove un’utenza con privilegi ordinari raggiunge operazioni riservate agli amministratori perché il controllo era stato messo nell’interfaccia grafica anziché nel servizio.
  3. Esposizione eccessiva di dati: il servizio restituisce l’intero oggetto e l’applicazione mostra soltanto i campi previsti. I campi nascosti dal client arrivano comunque, e sono leggibili da chi guarda la risposta.
  4. Assenza di limiti sulle richieste, che rende possibile provare grandi quantità di identificativi o di credenziali senza che nulla intervenga, e che su servizi a consumo produce anche un costo diretto.
  5. Gestione debole dell’autenticazione: token che non scadono, token trasmessi in posizioni che finiscono nei registri, verifiche incomplete sulla loro validità. Il rafforzamento dell’autenticazione a più fattori sul lato utente non protegge un’interfaccia che accetta un token scaduto.

Nessuna di queste è una vulnerabilità di un componente di terze parti, e nessuna comparirà in un avviso di sicurezza. Sono difetti di progettazione che esistono soltanto nella vostra implementazione, e la distinzione tra un bug irrilevante e uno sfruttabile passa esattamente da qui, come abbiamo visto parlando di quando un difetto diventa una vulnerabilità.

Verificare un’interfaccia di programmazione richiede di interrogarla come farebbe un client ostile, con credenziali valide e ipotesi sulle sue logiche: è la parte del perimetro applicativo dove il ragionamento conta più dello strumento.

Scopri il web application penetration test

Perché gli strumenti automatici non bastano

Uno strumento di scansione lavora bene quando può percorrere una struttura e confrontare ciò che trova con un elenco di problemi noti. Sulle interfacce di programmazione entrambe le condizioni cadono.

La prima cade perché non c’è una struttura da percorrere: senza la documentazione formale del servizio, lo strumento non sa quali endpoint esistono né quali parametri accettano. La seconda cade perché i difetti che contano non sono nell’elenco di nessuno: il controllo di autorizzazione mancante su una risorsa specifica della vostra applicazione non ha un identificativo pubblico, non ha un punteggio di gravità assegnato e non comparirà mai in un bollettino.

C’è poi un ostacolo pratico che si aggiunge ai due: per verificare un controllo di autorizzazione serve essere autenticati, e serve esserlo con almeno due utenze diverse. Il difetto si manifesta soltanto confrontando cosa vede l’utenza A quando chiede una risorsa dell’utenza B, e questo richiede di conoscere il modello dei ruoli dell’applicazione. È il motivo per cui su questo perimetro la modalità di verifica più efficace è quella in cui l’analista riceve documentazione e credenziali invece di partire alla cieca.

Il risultato pratico di questa differenza si vede nei report. Una scansione su un’applicazione con interfacce restituisce un elenco di segnalazioni sui componenti, quasi sempre con la prioritizzazione che abbiamo descritto a proposito di come ordinare le vulnerabilità; una verifica manuale restituisce le due o tre condizioni in cui un cliente può leggere i dati di un altro. Le seconde sono meno numerose e sono quelle che contano.

Chi possiede l’API: la parte organizzativa

Sotto i difetti tecnici c’è quasi sempre una questione di proprietà. Un’interfaccia nasce per un progetto, viene consegnata da un fornitore o sviluppata internamente, entra in produzione e poi non ha più un responsabile: il progetto è chiuso, chi l’aveva richiesta è passato ad altro, e il servizio continua a rispondere.

Le domande che rendono governabile questo perimetro sono quattro. Chi è il responsabile di ciascuna interfaccia esposta, con nome e non con reparto. Quali versioni sono attive e quali dovrebbero essere state spente. Chi consuma ciascuna di esse, perché è l’informazione che serve per poterla dismettere. E quali interfacce di terzi consumate voi, con quali dati in uscita — che è il fronte su cui le discipline in materia di sicurezza chiedono oggi una valutazione documentata dei fornitori.

Su tutte pesa la registrazione degli eventi. Un’interfaccia che risponde senza tracciare chi ha chiesto cosa non permette di accorgersi di un accesso anomalo né di ricostruirlo dopo: sul perché la raccolta ordinata dei registri sia il presupposto di qualsiasi indagine abbiamo scritto nella guida al log management.

In conclusione

Le interfacce di programmazione sono la parte dell’applicazione che regge il servizio e che meno spesso viene verificata, per una ragione strutturale: non si vedono navigando, non compaiono negli inventari e non presentano vulnerabilità catalogate. I difetti che le riguardano sono controlli mancanti, e i controlli mancanti non hanno un bollettino.

Il che porta a una conclusione operativa semplice: una verifica che non include esplicitamente le interfacce nel perimetro non le ha esaminate. Vale la pena controllarlo sul report che avete in mano, prima di considerarlo completo.

Inventario delle interfacce esposte, responsabilità, versioni da dismettere e valutazione dei servizi di terzi che consumate: sono decisioni che precedono la verifica tecnica e ne definiscono il perimetro.

Parla con i nostri consulenti


    Dichiaro di aver letto e compreso l'Informativa sul trattamento dei dati