← Blog

La tua libreria HTTP sta facendo trapelare le tue chiavi API?

La tua applicazione chiama un'API con una chiave segreta in un header - Authorization, oppure qualcosa di custom come X-API-Key. Ti fidi che quella chiave vada solo all'host che ti aspetti. Poi quell'host, un giorno, risponde con un redirect 302 verso un altro indirizzo. La tua libreria HTTP, come fa di default, segue il redirect. Domanda da un milione di dollari: la tua chiave segreta viene inviata anche alla nuova destinazione?

La risposta corretta sarebbe "no". È anche la risposta che la maggior parte degli sviluppatori darebbe senza pensarci. Ma in troppe librerie HTTP tra le più usate al mondo la risposta reale è "dipende" - e "dipende", quando si parla di una credenziale, è già di per sé una vulnerabilità. Questo articolo spiega perché succede, ti dà un test da eseguire in trenta secondi per scoprire se sei esposto, e ti mostra come chiudere il buco senza aspettare che qualcun altro lo faccia per te.

Cosa dovrebbe succedere (e cosa succede davvero)

Il comportamento corretto poggia su un concetto preciso: l'origine. Sul web un'origine non è il dominio, è la tripla (schema, host, porta). https://api.example.com e https://api.example.com:8443 sono due origini diverse, esattamente come lo sono example.com e evil.com. La regola è semplice: le credenziali appartengono all'origine a cui le hai destinate, e non dovrebbero mai attraversare un cambio di origine senza una tua decisione esplicita.

Quasi tutte le librerie implementano la versione facile di questa regola: se il redirect punta a un dominio diverso, rimuovono gli header sensibili. Il problema è quali header considerano sensibili. Quasi sempre la lista è cablata e cortissima: Authorization, Cookie, Proxy-Authorization. Fine. Se la tua applicazione autentica con un header custom - e moltissime lo fanno: X-API-Key, X-Auth-Token, Api-Key, Token - la libreria non ha modo di sapere che quell'header è una credenziale. Quindi lo tratta come un header qualunque e lo porta con sé alla destinazione del redirect.

La tua app X-API-Key api.example.com 302 redirect attacker.com la tua chiave trapela qui
La credenziale viaggia oltre il confine di origine, fino a un host che non avrebbe mai dovuto vederla.

Provalo tu stesso in trenta secondi

Non devi credermi sulla parola. Apri un terminale e fai seguire a curl un redirect cross-host con un header custom, mandandolo a un endpoint che ti rimanda indietro gli header ricevuti:

curl -sSL -H "X-API-Key: segreto-da-non-perdere"   "https://httpbin.org/redirect-to?url=https://postman-echo.com/get&status_code=302"

La prima URL è su httpbin.org, ma risponde con un 302 verso postman-echo.com - un host diverso. Nella risposta finale, guarda l'oggetto degli header ricevuti: ci trovi il tuo X-API-Key, viaggiato allegramente da un'origine all'altra. Il tuo client HTTP applicativo, nella stragrande maggioranza dei casi, si comporta esattamente così. Quello che hai appena visto con curl è lo stesso meccanismo che fa uscire le chiavi dalle applicazioni vere.

I tre punti ciechi

Riassumendo dove si rompe, in ordine di frequenza:

  • Header custom non coperti. La protezione strippa Authorization ma ignora X-API-Key e simili. È il caso più comune e più sottovalutato, perché lo sviluppatore pensa di essere al sicuro proprio perché usa un header "suo".
  • Confusione di porta. Un redirect da http://host:8080 a https://host:9443 è un cambio di origine (la porta è diversa). Diverse librerie confrontavano solo l'hostname, concludevano "stesso host" e si tenevano le credenziali. Lo stesso vale per l'upgrade da http a https trattato come "sicuro" a prescindere.
  • Catene di redirect. Il caso base singolo viene gestito, ma una catena - A rimanda a B che rimanda a C - o un redirect che passa da un intermediario, possono far ricomparire un header che era stato tolto al primo salto.

Non è un caso isolato. È ovunque.

So che è ovunque perché l'ho cercato sistematicamente, una libreria dopo l'altra. La stessa classe di bug, confermata in sei librerie HTTP molto diffuse tra gli ecosistemi Node.js e Go: undici (il client dietro il fetch globale di Node.js), node-fetch, follow-redirects (la dipendenza di redirect di axios, presente in mezzo ecosistema npm), go-resty, req e gorequest - più una CVE pubblicata su una di queste. Non parliamo di progetti abbandonati: sono componenti che girano in produzione dentro milioni di applicazioni, con milioni di download alla settimana. Il punto non è che gli autori siano sprovveduti - è che questo confine di fiducia è così facile da dare per scontato che ci cascano tutti. Nessuno testa la propria libreria HTTP, perché "funziona". Ed è esattamente lì che si nascondono i bug peggiori: nei pezzi che nessuno guarda più.

Quando diventa un attacco vero

"Ok, ma serve un attaccante che controlli un redirect": vero, è meno raro di quanto sembri. Tre scenari concreti:

  • Webhook e URL configurabili. La tua app permette al cliente di impostare un URL di callback? Se quella richiesta viaggia con una credenziale e segue redirect, il cliente (o chi gli ha bucato l'account) può puntarla a un server che risponde 302 e raccoglie l'header.
  • Integrazioni di terze parti. Chiami un servizio esterno con la tua chiave. Quel servizio, compromesso o malevolo, risponde con un redirect verso un host che controlla. La tua chiave parte da sola.
  • Contesti cloud e service-to-service. Tra microservizi i redirect sono pane quotidiano, e le credenziali (token, API key interne) girano in continuazione. Un singolo servizio compromesso che sa rispondere con un redirect diventa un punto di raccolta.

In tutti e tre i casi l'impatto è lo stesso: esfiltrazione di credenziali valide, in chiaro, verso un'origine che non avrebbe mai dovuto vederle. Da lì in poi è account takeover, accesso ai dati, movimento laterale.

Come metterti al sicuro

La cosa importante: non aspettare la patch della libreria. Puoi chiudere il buco a livello applicativo oggi, con un principio guida - tratta ogni redirect su una richiesta autenticata come un confine di fiducia, non come un dettaglio di trasporto - e tre tattiche.

1. Gestisci i redirect a mano per le chiamate autenticate. Disabilita il following automatico e decidi tu se e dove ri-mandare la credenziale. In axios:

const res = await axios.get(url, {
  headers: { "X-API-Key": secret },
  maxRedirects: 0,                 // non seguire in automatico
  validateStatus: (s) => s < 400, // gestisci 3xx tu stesso
});

2. Spoglia gli header sensibili a ogni salto. In Go con net/http hai CheckRedirect, che ti lascia mutare la richiesta a ogni hop:

client := &http.Client{
  CheckRedirect: func(req *http.Request, via []*http.Request) error {
    req.Header.Del("X-API-Key")
    req.Header.Del("Authorization")
    return nil
  },
}

3. Vincola la destinazione. Dove la libreria lo permette, estendi la lista degli header da rimuovere con i tuoi header custom (follow-redirects, ad esempio, ha aggiunto un'opzione apposita dopo le segnalazioni), e quando puoi accetta redirect solo verso un'allowlist di host attesi, invece di seguire ciecamente qualunque Location.

La checklist in breve

  • Mandi credenziali in header custom (non solo Authorization)? Sei nella categoria a rischio.
  • Il tuo client segue i redirect di default? Quasi certamente sì.
  • Qualche endpoint che chiami può essere indotto a rispondere con un redirect? Webhook, URL configurabili, integrazioni: trattali come non fidati.
  • Per le chiamate autenticate verso l'esterno: redirect manuali, header sensibili strippati a ogni hop, destinazioni in allowlist.

La lezione più grande

La sicurezza della tua applicazione non vive solo nel codice che scrivi. Vive anche nelle decine di dipendenze che la tua app si trascina dietro, e nelle assunzioni che quelle dipendenze prendono al posto tuo - assunzioni che non hai mai letto, su comportamenti che dai per scontati. Una di quelle assunzioni, in un componente che usi ogni giorno senza pensarci, può prendere la tua chiave più preziosa e consegnarla a un perfetto sconosciuto. Il lavoro del difensore, oggi, è sapere quali assunzioni stai ereditando - e non fidarti di nessuna che riguardi una credenziale.

Hai bisogno di un parere esperto?

Se vuoi approfondire questo argomento o ti serve una consulenza specializzata, parliamone.

Parliamone