"Sicurezza in Firebase" sono due cose che conviene tenere separate. La prima è il modello di Firebase: il browser parla direttamente con il database e lo storage, quindi non c'è un server che filtra, e la protezione vive nelle regole, in App Check e nella configurazione del progetto. La seconda è ciò che Lovable, Bolt o Cursor fanno con Firebase quando generano codice, ed è da lì che arrivano quasi tutti i buchi. Questa guida spiega il modello, ripassa ciò che l'IA sbaglia, ti lascia un firebase.json e delle regole base da incollare, un prompt di revisione e la verifica dall'esterno. I dieci errori di regole più comuni, con la regola sbagliata e quella giusta, sono in gli errori di sicurezza più comuni in Firebase.
Parte 1: come funziona la sicurezza in Firebase
Il client parla con i servizi, non con il tuo server
In una tipica app Firebase non c'è un backend tuo: l'SDK del browser legge e scrive direttamente su Firestore, Realtime Database e Storage. Significa che l'oggetto di configurazione con apiKey e projectId è pubblico per design (identifica il progetto, non autorizza nulla) e che l'unica barriera tra un visitatore e i tuoi dati sono le regole di sicurezza. Ogni prodotto ha le sue: Firestore, Realtime Database e Storage si configurano separatamente, e un'app di solito ha aperto quello che nessuno ha guardato.
Le regole rispondono a "chi può cosa"
Una regola riceve la richiesta con l'utente autenticato (request.auth), il documento che si vuole leggere o scrivere e i nuovi dati (request.resource.data). Con questo decide. La distinzione chiave è tra autenticato (c'è una sessione) e autorizzato (quella sessione può vedere quel documento): request.auth != null controlla solo il primo, e registrarsi è gratis. Le regole validano anche ciò che si scrive, perché un utente non si metta isAdmin: true nel proprio profilo.
Cosa protegge oltre alle regole
- App Check. Richiede che le richieste arrivino dalla tua app reale (con reCAPTCHA o Play Integrity) e non da uno script con il tuo
projectId. Frena gli abusi e le fatture inattese per letture massive. - Restrizione della chiave API. Nella console di Google Cloud, limita la chiave ai domini del tuo sito e alle API che usi. Non sostituisce le regole, ma chiude una porta.
- Auth. Domini autorizzati per l'accesso, protezione dall'enumerazione delle email, verifica dell'email, solo i metodi di accesso che usi davvero, autenticazione a più fattori se gestisci dati sensibili.
- Cloud Functions come server. Tutto ciò che ha bisogno di una chiave segreta (pagamenti, email, IA) va in una funzione, con il segreto in Secret Manager, e il client chiama la funzione. Attenzione: una funzione HTTP è pubblica per tutta internet a meno che tu non verifichi il token dell'utente o usi una funzione callable con App Check.
- Budget. Firebase fa pagare per lettura e per invocazione. Avvisi di budget in Google Cloud e limiti nelle regole (
request.query.limit) evitano che un loop o un attaccante ti lascino una fattura.
Hosting: cosa mette Firebase e cosa no
Firebase Hosting dà TLS automatico, CDN e reindirizzamento a HTTPS. Non mette header di sicurezza: si aggiungono in firebase.json. E serve tutto ciò che c'è nella cartella pubblica, compreso un .env copiato per errore.
Parte 2: cosa l'IA sbaglia con Firebase
- Regole in modalità test, e poi
if true. L'IA lascia le regole che aprono tutto per trenta giorni; alla scadenza l'app si rompe e la soluzione rapida è aprirle per sempre. request.auth != nullcome unica condizione. Qualsiasi utente registrato legge i dati di tutti gli altri.- Scritture senza validazione. Il profilo ha
roleocreditse la regola di update non esclude quei campi. - Altre chiavi nel bundle. Accanto alla configurazione di Firebase compaiono la chiave segreta di Stripe, quella di OpenAI o quella di un servizio email. Dettaglio in segreti che la tua app fa trapelare nel browser.
- Funzioni HTTP che non controllano l'utente. La funzione che incassa, invia email o chiama un modello risponde a chiunque conosca l'URL.
- Storage con regole copiate da Firestore.
allow read, write: if request.auth != nullinstorage.rules: qualsiasi utente legge i file degli altri e carica quello che vuole. - Senza App Check, senza header, senza avvisi. Tre caselle che nessuno spunta perché l'app "funziona già".
Un blocco da incollare nel tuo progetto
Header di sicurezza in firebase.json (la Content-Security-Policy va a parte perché dipende dai tuoi script):
{
"hosting": {
"public": "dist",
"headers": [
{
"source": "**",
"headers": [
{ "key": "Strict-Transport-Security", "value": "max-age=63072000; includeSubDomains; preload" },
{ "key": "X-Content-Type-Options", "value": "nosniff" },
{ "key": "X-Frame-Options", "value": "DENY" },
{ "key": "Referrer-Policy", "value": "strict-origin-when-cross-origin" },
{ "key": "Permissions-Policy", "value": "camera=(), microphone=(), geolocation=()" }
]
}
]
}
}
E un punto di partenza per firestore.rules: tutto chiuso di default, ogni utente il proprio documento e campi di privilegio protetti.
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /users/{userId} {
allow read: if request.auth != null && request.auth.uid == userId;
allow create: if request.auth != null && request.auth.uid == userId
&& !request.resource.data.keys().hasAny(['role', 'isAdmin', 'plan', 'credits']);
allow update: if request.auth != null && request.auth.uid == userId
&& !request.resource.data.diff(resource.data).affectedKeys()
.hasAny(['role', 'isAdmin', 'plan', 'credits']);
}
match /{document=**} {
allow read, write: if false;
}
}
}
Aggiungi poi una regola esplicita per collezione; l'ultima, con if false, garantisce che qualsiasi collezione nuova nasca chiusa.
Un prompt di revisione prima di pubblicare
Rivedi la sicurezza di questa app con Firebase e non cambiare ancora nulla. Rispondi con una lista:
1. Regole di Firestore, Realtime Database e Storage che permettono l'accesso a chiunque, con data in modalità test o con request.auth != null come unica condizione.
2. Regole di scrittura che non validano i campi, in particolare role, isAdmin, plan o credits.
3. Chiavi diverse dalla configurazione di Firebase presenti nel codice del browser, con file e riga.
4. Cloud Functions HTTP che non verificano il token dell'utente, e funzioni che leggono segreti dal codice invece che da Secret Manager.
5. Se App Check è attivo e se la chiave API è limitata per dominio.
6. Header di sicurezza in firebase.json e file nella cartella pubblica che non dovrebbero esserci.
Per ogni punto, proponi la regola o la modifica esatta e aspetta la mia conferma.
Verifica il risultato dall'esterno
Il tuo projectId è nel bundle, quindi chiunque può fare questo. L'API REST di Firestore senza token:
curl -s "https://firestore.googleapis.com/v1/projects/TUO_PROGETTO/databases/(default)/documents/users" | head -c 400
curl -sI https://tuodominio.com | grep -iE "strict-transport|x-frame|x-content-type"
Il risultato corretto è un errore di permessi sul primo (se restituisce documenti, la collezione è aperta) e gli header sul secondo. Ripeti il primo con ogni collezione e con Storage. Scanaris fa queste verifiche e una quarantina di altre in 30 secondi: rileva la configurazione di Firebase nel tuo bundle, prova le collezioni abituali senza autenticazione, cerca altre chiavi nel JavaScript, controlla header, CORS, cookie e file esposti, e ti dà un fix prompt per ogni riscontro da incollare in Lovable, Bolt o Cursor. Se la tua app usa Supabase invece di Firebase, la guida Supabase è l'equivalente.
Domande frequenti
Devo nascondere l'apiKey di Firebase?
No. È pubblica per design e identifica il progetto. A proteggere i dati sono le regole e App Check. Quello che conviene fare è limitarla ai tuoi domini in Google Cloud.
Le Cloud Functions sono private?
Una funzione HTTP è un URL pubblico. Verifica il token dell'utente dentro la funzione o usa funzioni callable con App Check. Le funzioni che reagiscono a eventi (un documento creato, un file caricato) non hanno URL e sono davvero interne.
Come provo le regole senza rompere l'app?
Con il simulatore della console (scheda Regole) per provare letture specifiche, e con l'emulatore locale per i test automatici. Cambia le regole con l'app aperta in un'altra scheda e verifica che ciò che deve funzionare continui a funzionare.