Basi della sicurezza
Una chiave AWS esposta nel frontend non è come una chiave OpenAI
Una chiave di accesso AWS esposta nel tuo frontend legge e scrive il tuo storage. La soluzione di solito è una presigned URL, non una chiave nuova.

In breve
- Una chiave di accesso AWS esposta nel tuo frontend è un problema diverso da quello di una chiave che può solo spendere soldi. Cosa raggiunge lo decidono i suoi permessi.
- Due stringhe firmano una richiesta AWS: un identificatore che inizia con `AKIA`, e una metà segreta. Una senza l'altra non firma niente.
- Una chiave nuova incollata nello stesso posto è lo stesso ritrovamento con un valore diverso. La soluzione è una presigned URL, così il browser non tiene nessuna credenziale.
- Ne abbiamo trovata una in 9 delle 31.056 app scansionate in cui quel controllo è arrivato in fondo.
Qualcuno apre la tua app in un browser, preme F12 e trova una stringa che
inizia con AKIA dentro il tuo codice frontend. Oppure GitHub ti scrive che un
commit caricato a marzo porta una credenziale AWS. Il consiglio che arriva con
entrambe le cose è sempre lo stesso: ruota la chiave. Per la maggior parte
delle chiavi quella è quasi tutta la risposta.
Ecco la parte che guida dopo guida sbaglia. Una chiave di accesso AWS esposta nel tuo frontend non è una chiave che spende soldi. È una chiave che apre cose, e le due vanno storte in direzioni diverse. Una chiave che spende soltanto è una carta aziendale: qualcuno fa un conto, tu blocchi la carta, e il danno è una cifra che leggi su un estratto. Una chiave che apre cose è il mazzo del magazzino. Cosa raggiunge dipende da cosa ci hanno scritto sopra quando è stata fatta, e lo leggi su una sola schermata della tua console AWS.
Cosa significa AKIA all'inizio di una chiave?
Segna una chiave di accesso a lunga durata, che appartiene a un utente del tuo
account oppure al login root dell'account. AWS scrive il prefisso nella propria
guida agli identificatori: AKIA per le chiavi di accesso e ASIA per quelle
temporanee che distribuisce il servizio di token. Quindi i primi quattro
caratteri ti dicono con quale tipo hai a che fare, e AKIA è il tipo senza
scadenza. Funziona finché qualcuno non la spegne.
Una credenziale AWS sono due stringhe, e una richiesta ha bisogno di entrambe
per essere firmata. La prima è l'identificatore della chiave di accesso, la
parte che inizia con AKIA. La seconda è la chiave di accesso segreta, una
stringa più lunga senza nessun prefisso davanti. L'identificatore da solo non
firma niente.
Vale la pena controllarlo prima di decidere quanto sia brutta questa mattina,
perché cambia la risposta. Se il tuo bundle porta la stringa AKIA e niente
che somigli alla sua metà segreta, un visitatore che ha letto la tua pagina si
è portato via il nome della chiave e non la chiave. In pratica le due viaggiano
insieme, perché quello che ha messo una nel browser le ha messe entrambe: una
coppia di variabili d'ambiente chiamate AWS_ACCESS_KEY_ID e
AWS_SECRET_ACCESS_KEY, lette da codice che doveva girare su un server.
Cosa può fare qualcuno con la mia chiave di accesso AWS?
Quello che i suoi permessi consentono, e niente oltre. Quindi le risposte sono tre.
Cosa può leggere? Ogni bucket S3 che la policy elenca, e ogni oggetto dentro, compresi quelli a cui non hai mai messo un link da nessuna parte. Un bucket che niente nella tua app nomina non è nascosto a una credenziale che può elencarlo.
Cosa può scrivere? Gli stessi posti, ed è la metà che si dimentica. Una chiave che può scrivere può anche sovrascrivere e cancellare, e un file sostituito sul posto sembra identico a quello che hai caricato finché qualcuno non lo apre.
Cosa può avviare? Questa è quella col tassametro. Una policy abbastanza larga da far partire del calcolo fa partire del calcolo, e quello fattura a ore finché gira. Niente nella copia che ha il browser limita quanta parte del tuo account raggiunge; la policy è l'unico limite che esiste.
La versione peggiore di tutto questo è una chiave fatta per il login root
dell'account. AWS scrive nelle proprie indicazioni sull'utente root che questo
ha accesso senza restrizioni a tutti i servizi AWS, alle risorse e ai dati di
fatturazione, e sconsiglia di creargli chiavi di accesso. Se la chiave nella
tua pagina inizia con AKIA e appartiene all'utente root, quello che è esposto
è l'intero account e non un bucket.
Quindi non tirare a indovinare su niente di tutto questo. Apri IAM, trova l'utente a cui appartiene la chiave e leggi le policy agganciate. È una schermata, e risponde a tutte e tre le domande qui sopra.
Basta ruotarla?
Disattiva oggi la chiave esposta, e non mettere una sostituta nello stesso posto.
Disattivare è la prima mossa giusta ed è più gentile di come suona. AWS lascia a un utente fino a due chiavi di accesso attive insieme, e questo esiste proprio perché una sostituta possa salire prima che la vecchia scenda. Disattivare lascia la chiave lì e spenta, e si può riaccendere; cancellare è irreversibile, e la metà segreta di una chiave cancellata non si recupera. Quindi disattiva, guarda cosa si rompe e cancella dopo.
Quello che non chiude la faccenda è creare una chiave nuova e incollarla dove
stava la vecchia. La fuga non riguardava davvero quel singolo valore.
Riguardava un browser che tiene una credenziale senza scadenza, e tutto quello
che la tua pagina scarica lo scarica ogni visitatore. Una stringa AKIA appena
fatta nello stesso bundle torna come lo stesso ritrovamento alla scansione
successiva.
AWS lo dice chiaramente nella propria guida di audit della sicurezza, parlando di app mobili: non dovrebbero mai contenere chiavi di accesso incorporate, nemmeno cifrate. Un bundle del browser si legge più facilmente di un binario, quindi la stessa risposta vale qui e costa meno lavoro a un estraneo.
Se hai già trovato la chiave in un posto pubblico, l'ordine in cui lavori conta, e cosa fare quando trapela una chiave API mette in fila quell'ordine per chiavi di ogni tipo.
Cosa fa invece una presigned URL
Lascia che il browser faccia una cosa sola su un file solo senza tenere nessuna credenziale.
Il tuo server si tiene la chiave di accesso, dove un visitatore non può leggerla. Quando la tua pagina deve mettere un file in S3 o tirarne fuori uno, lo chiede al tuo server, e il tuo server firma una URL per quell'oggetto e quell'azione e la restituisce. Il browser usa la URL e non si porta dietro nient'altro. AWS descrive una presigned URL come accesso temporaneo agli oggetti S3 senza credenziali AWS, e lo stesso meccanismo copre download e upload.
Torniamo al magazzino. Una presigned URL è incontrare il corriere alla porta con la cassa che era venuto a prendere, invece di passargli il mazzo e sperare che la trovi. Quello che il corriere si porta via smette di funzionare quando il suo orologio finisce.
Per il caso in cui ogni persona autenticata arriva ai propri file, AWS indica
di nuovo altrove: le sue indicazioni su come proteggere le chiavi di accesso
dicono che le app mobili dovrebbero usare Amazon Cognito per le identità invece
di incorporare chiavi di accesso. Quello che Cognito dà al browser è una
credenziale temporanea, il tipo ASIA dall'inizio di questo articolo, che
smette di funzionare da sola dopo un po'. Una copia raschiata dalla tua pagina
un martedì è già morta il mercoledì, e questa è l'unica proprietà che una
chiave AKIA non ha.
Come verifico se la mia app spedisce una chiave AWS?
Cerca in quello che il browser ha scaricato, non in quello che sta nel progetto. Sono due file diversi, e quello che conta è quello che ricevono i tuoi visitatori.
Nel browser. Apri il tuo sito pubblicato, premi F12 e cerca AKIA nel
JavaScript caricato. Chrome ed Edge cercano in tutti i file caricati in una
volta dal pannello Sources.
Nel progetto. Cerca AKIA, AWS_ACCESS_KEY_ID e
AWS_SECRET_ACCESS_KEY. Poi cerca i due prefissi che mettono un valore nel
bundle apposta, VITE_ e NEXT_PUBLIC_, e leggi ogni valore dietro di loro.
Perché quei due prefissi pubblicano tutto quello che nominano
è la meccanica dietro la maggior parte di questi casi, ed è una regola della
build che nessuno ha digitato per sbaglio.
Da fuori. La nostra scansione gratuita legge il tuo sito pubblicato come farebbe un estraneo e dice quali credenziali vede in quello che hai spedito, questa compresa. Ci mette circa 20 secondi e non chiede un account: scansiona la tua app gratis.
Su tutte le app che abbiamo scansionato questo è un ritrovamento raro: una chiave di accesso AWS è saltata fuori in 9 delle 31.056 app in cui quel controllo è arrivato in fondo. Quelle che escono molto più spesso sono le chiavi Google, di solito a posto, e quelle di OpenAI, di solito no. Cosa esce davvero dalle app costruite così le mette tutte una accanto all'altra con i numeri.
Cosa ha fatto la chiave mentre era fuori
Apri la cronologia eventi di CloudTrail e filtrala sull'identificatore della chiave di accesso.
La cronologia eventi è accesa in ogni account AWS senza dover attivare niente, tiene gli ultimi 90 giorni e non costa nulla in più. Ogni voce porta l'identificatore della chiave che ha fatto la chiamata, quindi puoi rileggere cosa ha fatto la tua. Questo risponde alle domande sulla configurazione: un bucket creato, una policy cambiata, un utente aggiunto.
Poi c'è la parte che conviene sapere prima di andare a guardare. La cronologia tiene gli eventi di management. Leggere un oggetto da S3 è un evento di data, e AWS dice esplicitamente che i trail non li registrano per impostazione predefinita e che gli eventi di data non compaiono affatto nella cronologia. Accenderli registra da quel momento in avanti.
Quindi la lettura onesta è questa. Se la chiave è servita a cambiare il tuo account, il registro te lo mostra. Se è servita a scaricare il contenuto di un bucket, probabilmente no, e stai decidendo cosa dire ai tuoi clienti sapendo che può essere successo.
Come tenere una chiave fuori dalla prossima build
Una credenziale parte verso il browser al momento della build, quindi il prossimo deploy è quello da tenere d'occhio. La chiave che togli oggi torna dentro il pomeriggio in cui qualcuno aggiunge una funzione che ha bisogno di S3 e chiede a un agente di collegarla.
Reeve Monitor rilegge per te il tuo sito pubblicato:
- tutti e nove i controlli ogni ora, su un massimo di tre app
- un messaggio quando un risultato cambia, così una chiave arrivata di martedì non aspetta che tu guardi
- se l'app risponde, ogni 60 secondi
- un report mensile di quello che ha visto
Se la tua app tiene i dati in un progetto Supabase, Reeve Care ne conserva anche una copia:
- una copia cifrata del tuo database Supabase 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
Ognuno di quei nove controlli descrive cosa può raggiungere un estraneo. Una copia del database di ieri notte risponde all'altra domanda, quella su cosa qualcuno ha già cambiato mentre la chiave era fuori.
Cosa fare questa settimana
Cosa fare
- Apri il tuo sito pubblicato, premi F12 e cerca
AKIAnel JavaScript caricato. Quello è il file che hanno i tuoi visitatori, ed è l'unico che conta. - Se ne trovi una, disattivala oggi in IAM. Disattivare è reversibile e vale subito; cancellare no, e la metà segreta non si recupera.
- Leggi le policy agganciate all'utente della chiave prima di decidere quanto sia seria la cosa. Cosa può leggere, cosa può scrivere e cosa può avviare sono tre risposte separate.
- Cambia lo schema invece del valore. Il tuo server tiene la chiave e firma una presigned URL per un oggetto, oppure Amazon Cognito dà al browser una credenziale temporanea che scade da sola.
- Filtra la cronologia eventi di CloudTrail sulla chiave per gli ultimi 90 giorni. Ti mostra cosa ha configurato la chiave, e non ti mostra quali file ha letto a meno che gli eventi di data non fossero già accesi.
Parti dalla ricerca con F12, perché in un minuto risolve se hai un problema o no. Se salta fuori qualcosa, la checklist di sicurezza in 10 minuti copre il resto di quello che un'app appena lanciata tende a lasciare aperto, e spostare un segreto in una edge function è lo schema per ogni chiave che non sarebbe mai dovuta stare nella pagina.
FAQ
È mai sicuro mettere chiavi AWS nel codice del frontend?
No. Lo dice AWS nella propria guida di audit della sicurezza, parlando di app mobili: un'app non dovrebbe mai contenere chiavi di accesso incorporate, nemmeno cifrate. Un bundle del browser si legge più facilmente di un binario, quindi la stessa risposta vale qui e costa meno lavoro a un estraneo. Se la tua pagina deve davvero raggiungere S3, le strade previste sono una presigned URL firmata dal tuo server, oppure credenziali temporanee di Amazon Cognito, che scadono da sole.
Cosa può fare qualcuno con la mia chiave di accesso AWS?
Esattamente quello che i suoi permessi consentono, ed è per questo che non esiste una risposta sola. Una chiave agganciata a un utente con accesso in lettura a un bucket legge quel bucket. Una chiave agganciata a un amministratore fa tutto quello che fa un amministratore, compreso avviare macchine che fatturano a ore. Una chiave dell'utente root dell'account è il caso peggiore, perché AWS scrive che l'utente root ha accesso senza restrizioni a tutti i servizi, alle risorse e ai dati di fatturazione. Apri IAM e leggi le policy agganciate alla chiave prima di decidere quanto preoccuparti.
Che cos'è una presigned URL?
Una URL lunga che permette a un browser di fare una cosa sola su un file solo in S3, per un numero fissato di secondi, senza tenere nessuna credenziale AWS. Il tuo server tiene la chiave e firma la URL quando gliela chiedono. AWS descrive le presigned URL come accesso temporaneo agli oggetti S3 senza credenziali AWS, e funzionano sia per i download sia per gli upload.
Come verifico se la mia app spedisce una chiave AWS?
Cerca in quello che il tuo browser ha scaricato, non in quello che sta nel progetto. Apri il tuo sito pubblicato, premi F12 e cerca AKIA nel JavaScript caricato. Poi cerca nel progetto AKIA, AWS_ACCESS_KEY_ID e AWS_SECRET_ACCESS_KEY, e qualsiasi nome di variabile che inizi con VITE_ o NEXT_PUBLIC_ e ne contenga una, perché sono quei prefissi a mettere un valore nel bundle in partenza.
La mia chiave AWS è su GitHub. E adesso?
Disattivala prima in IAM, cosa reversibile e che vale subito, poi crea una sostituta per il server che ne aveva bisogno. Toglierla dal codice non chiude niente, perché il valore vecchio resta nella cronologia dei commit e in ogni clone che qualcuno abbia fatto. Dopo apri la cronologia eventi di CloudTrail e filtra sulla chiave per vedere cosa ha fatto.