Vai al contenuto

Basi della sicurezza

La tua chiave API è trapelata. L'ordine in cui muoverti

Una chiave API è trapelata e non sai da cosa cominciare. Non tutte le chiavi nel frontend lo sono, e l'ordine conta più della velocità.

Vlad Tkachenko12 min di lettura
Una tessera di accesso con una chiave disegnata sopra, davanti a un quadro di interruttori il cui primo interruttore è abbassato in posizione di spento.

In breve

  • Se una chiave API è trapelata, cosa fare per prima cosa dipende da quale chiave sia. Le chiavi pubblicabili stanno nel frontend e non chiedono nulla.
  • Se è un segreto vero, stabilisci se la chiave può spendere soldi. È l'unica parte di questa storia su cui corre un orologio.
  • Fermare una chiave e sostituire una chiave sono due comandi distinti presso ogni fornitore, e quasi tutti ti lasciano una finestra in cui funzionano entrambe.
  • Poi leggi il log del fornitore per il periodo in cui la chiave è stata fuori, e lascia stare la cronologia Git finché la chiave non è morta.

Il messaggio arriva quasi sempre da un report di scansione, da GitHub che ti avvisa che in uno dei tuoi repository è spuntato un segreto, o da qualcuno che ha premuto F12 sul tuo sito e ti ha mandato uno screenshot. Comunque ti sia arrivato, adesso sai che una tua chiave API è trapelata e non sai da cosa cominciare.

Ecco la parte che guida dopo guida sbaglia: danno la stessa risposta per ogni chiave, e la risposta è sempre ruotarla. Alcune di quelle chiavi devono essere pubbliche e non chiedono nulla. Fra le altre, alcune stanno gonfiando una fattura mentre leggi questa riga, e altre hanno fatto tutto il danno il giorno del deploy. Sono tre situazioni diverse, e la prima mossa cambia in ognuna.

Prima di tutto: quella chiave è davvero un segreto?

Spesso no, e i numeri pendono abbastanza da poterlo dire chiaramente.

Abbiamo scansionato 31.056 applicazioni online e letto il JavaScript che ciascuna consegna al browser. Il controllo che cerca credenziali ha potuto rispondere su tutte, e 1.332 sono tornate con almeno una chiave che meritava una segnalazione. 1.142 di quelle erano chiavi API di Google, che è l'unico tipo del gruppo a trovarsi di solito esattamente dove deve stare.

Una chiave API di Google dentro una pagina web è ciò che fa funzionare Google Maps. La chiave dice quale progetto paga, e ciò che impedisce a uno sconosciuto di spendere a tue spese è la restrizione sulla chiave invece della sua segretezza. La guida di Google è netta su entrambe le metà: "Unrestricted API keys are insecure", e "You are financially responsible for charges caused by abuse of unrestricted API keys." La riparazione per una chiave del genere consiste nell'aprirla nella Cloud Console e aggiungere due restrizioni, una che nomina il tuo sito e una che nomina le API che chiami davvero. La chiave in sé non cambia mai.

L'altra famiglia che sta nel browser sono le chiavi pubblicabili. Una chiave Stripe pk_live_, e una Supabase sb_publishable_ o anon, sono fatte perché le legga ogni visitatore che hai. Quali chiavi sono sicure nel frontend è la versione in quattro caratteri di quella prova.

Se preferisci non passare il bundle a mano, la nostra scansione gratuita legge il tuo sito online, elenca le chiavi che vede dall'esterno e dice di che tipo è ciascuna: scansiona la tua app. Richiede una ventina di secondi e non chiede alcun account.

La mia chiave API è trapelata. Cosa faccio per prima cosa?

Stabilisci se la chiave ha un contatore.

Una chiave con contatore ti addebita ogni richiesta. Quella di Google, quella di OpenAI, quella di Anthropic e una chiave AWS con i permessi sbagliati dietro sono tutti contatori: il traffico di qualcun altro atterra sulla tua fattura, a un ritmo che sceglie quella persona e che tu non vedi. Una chiave senza contatore legge o scrive invece i tuoi dati. Una chiave Supabase service_role è l'esempio più chiaro, e niente in essa costa denaro all'ora.

Quella sola domanda fissa l'ordine.

Se la chiave ha un contatore, fermala adesso. La funzione che la usava resta rotta finché non pubblichi la sostituta, ed è lo scambio giusto, perché la fattura è l'unica parte di questa storia che continua a crescere mentre tu pianifichi.

Se la chiave legge dati ed è stata pubblicata nel tuo bundle, la lettura è già avvenuta. Ogni visitatore che ha caricato la pagina ne ha una copia, e così ogni crawler andato a cercare esattamente quella stringa. Nulla peggiora mentre ricostruisci l'ordine giusto, e la cosa da non sbagliare è non chiuderti fuori dalla tua stessa applicazione lungo la strada.

La chiave in alto ti sta costando denaro mentre leggi questa riga. Quella in basso ha fatto tutto quello che poteva fare il giorno del deploy.

Cosa può fare davvero ogni tipo di chiave

ChiaveSpende denaroLegge i tuoi datiSi può limitare invece di sostituirla?Sostituirla rompe l'applicazione?
Supabase sb_publishable_ o anonNoSolo le righe che le tue regole permettonoIl suo posto è il browserNon pertinente
Stripe pk_live_NoNoIl suo posto è il browserNon pertinente
Google AIza…Sì, sulla tua fattura CloudNoSì, e Google dice di provare prima quelloLimitarla no. Ruotarla può.
Chiave OpenAI o AnthropicSì, al ritmo di uno sconosciutoI file e gli assistant del progettoNon esiste una variante pubblicabileSì, finché non la tiene un tuo server
Stripe sk_live_ o rk_live_SìSì, clienti e registri di pagamentoUna chiave ristretta è la versione strettaNo, c'è una finestra di sette giorni
AWS AKIA… più la metà segretaSì, compreso calcolo a oreI tuoi bucket S3Deactivate, ed è reversibileNo, puoi tenerne due alla volta
Supabase sb_secret_ o service_roleNoOgni riga di ogni tabellaNoSì, su un progetto più vecchio

Due note su quella tabella, perché entrambe cambiano cosa fai dopo.

Una chiave di accesso AWS sono due stringhe, un identificativo che comincia con AKIA e una metà segreta, e AWS pretende entrambe insieme per firmare una richiesta. Quindi una stringa AKIA da sola in un bundle non è utilizzabile, e il motivo per trattarla comunque come urgente è che le due metà vengono quasi sempre incollate insieme. Apri il file e cerca la seconda prima di decidere in quale caso ti trovi.

Il dettaglio per fornitore sta presso ciascun fornitore: una chiave OpenAI, una chiave API di Google, una chiave segreta Stripe e una chiave service_role di Supabase, che è l'unica con una procedura tutta sua.

Fermare la chiave e sostituire la chiave sono due pulsanti diversi

Ogni fornitore di quella tabella te li dà entrambi, e chi è nel panico afferra il secondo.

  • Google. Limitare una chiave non cambia la stringa, quindi la tua applicazione continua a funzionare. La loro guida di sicurezza mette questo prima di tutto il resto: "First try to restrict your API keys", e la rotazione è la terza opzione scendendo, per quando una restrizione non è possibile.
  • Stripe. Expire key ferma una chiave da sola, senza nessuna sostituta di mezzo. La loro posizione su quando usarlo non ha sfumature: "If a restricted or secret API key is exposed or compromised, rotate it immediately even if you aren't sure anyone saw it." Separano anche le due parole che tutti usano come sinonimi. Exposure è che la chiave sia diventata visibile dove non doveva. Compromise è la prova che qualcuno l'ha usata.
  • AWS. Deactivate è il comando, e la parte utile è che si può tornare indietro. AWS dice di non cancellare affatto la vecchia chiave finché stai ancora controllando: "we recommend that you do not immediately delete the first access key. Instead, choose Actions and then choose Deactivate." Se salta fuori che qualcosa che avevi dimenticato la usa ancora, la riaccendi.
  • Supabase, su un progetto più vecchio. C'è un solo interruttore, e copre entrambe le chiavi legacy. anon e service_role sono firmate dallo stesso segreto, quindi disattivare quella che vuoi eliminare ferma anche quella che usa il tuo frontend. I quattro passi che lo evitano conviene leggerli prima di toccare l'interruttore, non dopo.
Due comandi, e solo quello di sinistra chiude il buco. Quale afferri per primo è la decisione di cui parla questo articolo.

Leggere il log del periodo in cui la chiave è stata fuori

La finestra si apre con il deploy che ha pubblicato la chiave e si chiude quando l'hai fermata. È su quell'intervallo di date che filtri il log del fornitore.

Ogni fornitore della tabella ne tiene uno. Stripe mostra i log delle richieste di una singola chiave, dal menu a tre puntini accanto a quella chiave nella pagina delle API Keys. AWS mette una data di ultimo utilizzo su ogni chiave di accesso nella console IAM senza alcuna configurazione, e registra le chiamate stesse in CloudTrail. Google traccia l'uso per chiave nella Cloud Console, che è anche la lettura che la loro guida ti chiede di fare prima di cambiare qualsiasi cosa su una chiave. Supabase conserva log di API e di database per il progetto, e come restringere la finestra su una chiave Supabase dice cosa cercarvi dentro.

Quello che cerchi è traffico che non sai spiegare: richieste a tabelle o endpoint che la tua applicazione non tocca mai, volume in ore in cui nessuno la stava usando, cancellazioni che nessuno ha fatto. Poi guarda i dati stessi, perché un messaggio di assistenza su un record che è cambiato da solo è il modo in cui la maggior parte di questi casi viene davvero scoperta, e arriva settimane dopo.

Spesso non puoi averne la certezza, e Stripe dice altrettanto del proprio rilevamento: "Stripe doesn't guarantee detection of all exposed or compromised keys." Quindi "niente nel log" è un risultato, e vale la pena annotarlo con accanto l'intervallo di date.

Ruotare senza mettere giù l'applicazione

Tre dei quattro fornitori qui sopra ti lasciano una finestra in cui la vecchia e la nuova chiave funzionano entrambe, ed è ciò che evita il disservizio.

Stripe. "When you rotate a key in the Dashboard, both the old and new keys work for up to 7 days." La finestra di dialogo ha anche l'opzione Now, e la loro documentazione è esplicita: se la scegli, la vecchia chiave viene cancellata. È il pulsante dell'emergenza col contatore, non quello di una migrazione tranquilla. Il loro consiglio su quando lasciar andare la vecchia è una misura invece di una data: controlla i suoi log delle richieste e falla scadere solo dopo che il suo volume è rimasto a zero per qualche ora o qualche giorno.

Google. La rotazione crea la nuova chiave con tutte le restrizioni della vecchia e, nelle loro parole, "both the old and new key are accepted" durante la finestra in cui sposti le tue applicazioni. Se cancelli la vecchia troppo presto e qualcosa si rompe, c'è una via di ritorno: una chiave API di Google cancellata si può ripristinare entro 30 giorni.

AWS. La sequenza è nella loro documentazione e comincia dalla chiave nuova: crea la seconda chiave di accesso mentre la prima è ancora attiva, sposta ogni applicazione su di essa, controlla la data di ultimo utilizzo della vecchia, disattivala, e solo allora cancellala. Un tetto da mettere in conto: un utente IAM può tenere al massimo due chiavi di accesso, quindi una terza applicazione ancora su una vecchia chiave non ha dove andare.

Supabase, su un progetto più vecchio. Nessuna finestra. La rotazione diretta delle chiavi legacy anon e service_role non è più supportata, quindi invalidarne una è una migrazione alla nuova coppia di chiavi, e l'ordine dei quattro passi è ciò che tiene in piedi l'applicazione.

È ancora nella tua cronologia Git

Lo è, e la documentazione di GitHub su questo comincia mandandoti da un'altra parte.

La loro pagina sulla rimozione dei dati sensibili ti rimanda alla chiave: "if the sensitive data you need to remove is a secret (e.g. password/token/credential), as is often the case, then as a first step you need to revoke and/or rotate that secret", e poi: "Once the secret is revoked or rotated, it can no longer be used for access, and that may be sufficient to solve your problem. Going through the extra steps to rewrite the history and remove the secret may not be warranted."

Il motivo che danno è ciò che un force push non raggiunge. Dopo che hai riscritto la cronologia, i vecchi commit sono ancora lì "In any clones or forks of your repository" e "Directly via their SHA-1 hashes in cached views on GitHub". L'assistenza può ripulire le viste in cache e i riferimenti nelle pull request se lo chiedi, e traccia una linea propria: "will only assist in the removal of sensitive data in cases where we determine that the risk can't be mitigated by rotating affected credentials." Un fork si tiene la sua copia in ogni caso, e GitHub non può darti i contatti di chi lo possiede.

Quindi l'ordine che descrivono è quello pratico: revocare la chiave e poi decidere se riscrivere la cronologia valga i suoi effetti collaterali. Revocare raggiunge copie che una riscrittura non raggiunge, compresa quella in un clone di cui non sai nulla e quella in uno screenshot che qualcuno ha tenuto.

La stessa chiave, in tre copie che non puoi cancellare. Revocarla le sbarra tutte e tre in una volta.

Tenere la prossima fuori dal bundle

Una chiave entra nel tuo bundle attraverso un deploy, e i deploy continuano. Ognuno di essi è un'altra occasione perché un valore che hai messo in un pannello dei segreti finisca in un file che il browser scarica. È per questo che un controllo fatto il mese scorso descrive l'applicazione del mese scorso.

La nostra scansione gratuita risponde alla domanda con cui sei arrivato qui.

  • i nove controlli sulla tua URL online, in una ventina di secondi
  • ogni chiave che vede dall'esterno, classificata e non soltanto trovata
  • un voto e i rilievi, senza account

Reeve Monitor rilancia quei controlli senza che tu lo chieda.

  • tutti e nove i controlli ogni ora, su un massimo di tre applicazioni
  • un messaggio quando un risultato cambia, così la chiave partita col deploy di stanotte non aspetta che tu vada a guardare
  • se l'applicazione risponde, ogni 60 secondi
  • un report mensile di quello che ha visto

Reeve Care conserva una copia del tuo database Supabase, per le chiavi che sanno scrivere.

  • una copia cifrata ogni notte, tenuta dove il tuo progetto non arriva
  • ogni copia verificata prima di contare, contando le righe di ogni tabella
  • un ripristino con un clic quando ti serve
  • anche i tuoi file caricati, appena colleghi una credenziale Storage
  • tutto quello che fa Monitor

Una chiave trapelata che sa solo leggere lascia i tuoi dati dove erano. Una chiave service_role, o una chiave AWS con permessi di scrittura, può svuotare una tabella, e nessuna rotazione successiva riporta indietro le righe. Il giorno in cui un agente IA ha cancellato un database di produzione racconta com'è vista da dentro.

Cosa fare adesso

Cosa fare

  • Identifica la chiave prima di toccarla. Una chiave Supabase anon o sb_publishable_ e una Stripe pk_live_ stanno dove devono stare, e delle 1.332 applicazioni in cui abbiamo trovato una chiave da segnalare, 1.142 avevano una chiave API di Google, che chiede una restrizione invece di una rotazione.
  • Chiediti se ha un contatore. Se le richieste di qualcun altro atterrano sulla tua fattura, ferma la chiave adesso e lascia che la funzione si rompa.
  • Usa il comando che ferma tanto quanto quello che sostituisce: Expire key su Stripe, Deactivate su AWS, una restrizione per sito e per API su Google.
  • Sostituiscila poi dentro la finestra del fornitore. Stripe ti dà sette giorni con entrambe le chiavi attive, Google le accetta entrambe mentre migri, e AWS ti lascia tenere due chiavi di accesso alla volta.
  • Leggi il log del fornitore per il periodo fra il deploy e lo stop, e annota cosa hai trovato, compreso "niente".
  • Lascia la cronologia Git per ultima. Una volta revocata la chiave, la guida di GitHub dice che riscrivere la cronologia può non valerne affatto la pena.

Se preferisci percorrere tutto questo come una lista, la checklist di sicurezza in 10 minuti copre questo argomento e le altre cose che conviene spegnere in un'applicazione appena lanciata.

FAQ

La mia chiave API è trapelata. Cosa faccio per prima cosa?

Stabilisci se la chiave può spendere soldi. Una chiave che ti addebita ogni richiesta ti sta costando qualcosa proprio adesso, quindi fermala subito e accetta che la funzione che la usa resti rotta per qualche minuto. Una chiave che legge soltanto dei dati, se era pubblica, è già stata letta: prenditi il tempo di fare la sostituzione in un ordine che non ti chiuda fuori dalla tua stessa applicazione.

Revocare o ruotare per primo?

Revocare per primo, se la chiave ha un contatore. Fermare la vecchia chiave ed emetterne una nuova sono due comandi separati presso ogni fornitore, e solo il primo chiude il buco. L'eccezione è una chiave che puoi limitare invece di sostituire: Google ti dice di provare una restrizione per sito e per API prima ancora di ruotare una chiave API di Google.

Come capisco se qualcuno ha usato la mia chiave?

Restringi la finestra al periodo fra il deploy che ha pubblicato la chiave e il momento in cui l'hai fermata, poi leggi il log del fornitore su quell'intervallo. Stripe mostra i log delle richieste per singola chiave, AWS mostra una data di ultimo utilizzo sulla chiave di accesso e registra le chiamate in CloudTrail, Google traccia l'uso per chiave, e Supabase conserva log di API e di database. Cerchi richieste verso cose che la tua applicazione non tocca mai e traffico in ore in cui nessuno la stava usando. Spesso non puoi averne la certezza, ed è un esito normale.

Ruotare la chiave romperà la mia applicazione?

Di solito no, se usi la finestra che il fornitore ti dà. Stripe tiene la vecchia e la nuova chiave attive insieme fino a sette giorni. Google emette la nuova chiave con le restrizioni della vecchia e accetta entrambe mentre migri. AWS ti lascia tenere due chiavi di accesso alla volta, quindi la nuova è già viva prima che la vecchia se ne vada. L'eccezione è un progetto Supabase più vecchio, dove l'interruttore che disattiva le chiavi legacy si porta via anche la chiave del frontend.

La chiave è nella mia cronologia Git. Basta cancellare il file?

No, e neanche riscrivere la cronologia è probabilmente la risposta. La documentazione di GitHub dice di revocare o ruotare il segreto per primo, e che una volta fatto, mettersi a riscrivere la cronologia può non valerne la pena. Un force push non raggiunge le copie nei fork e nei cloni, né le viste in cache raggiungibili dall'hash del commit. Rendere la chiave inutilizzabile copre tutte le copie in una volta.

Scritto da

Vlad Tkachenko

Fondatore di Reeve

Passo le giornate a guardare app costruite con Lovable, Bolt, v0, Cursor e Replit, e la breve lista di errori che vi ricompaiono di continuo.

Altro sull'autore

Da leggere dopo

Tutti gli articoli

Non sai come sta messa la tua app?

Esegui una scansione gratuita e ottieni un voto chiaro da A a F in una ventina di secondi. Senza account e senza carta.

Scansiona la tua app gratis

Controllo esterno automatizzato, non un audit completo. L'assenza di risultati non è una garanzia di sicurezza.