„Bezpieczeństwo Firebase" to dwie rzeczy, które warto rozdzielić. Pierwsza to model Firebase: przeglądarka rozmawia bezpośrednio z bazą danych i magazynem plików, więc nie ma serwera, który filtruje, a ochrona żyje w regułach, w App Check i w konfiguracji projektu. Druga to to, co Lovable, Bolt czy Cursor robią z Firebase przy generowaniu kodu, i stamtąd biorą się niemal wszystkie dziury. Ten przewodnik wyjaśnia model, omawia, co AI robi źle, zostawia Ci firebase.json i bazowe reguły do wklejenia, prompt do przeglądu i kontrolę z zewnątrz. Dziesięć najczęstszych błędów w regułach, ze złą i dobrą regułą, jest w najczęstsze błędy bezpieczeństwa w Firebase.
Część 1: jak działa bezpieczeństwo w Firebase
Klient rozmawia z usługami, nie z Twoim serwerem
W typowej aplikacji Firebase nie ma własnego backendu: SDK w przeglądarce czyta i zapisuje bezpośrednio do Firestore, Realtime Database i Storage. To oznacza, że obiekt konfiguracji z apiKey i projectId jest publiczny z założenia (identyfikuje projekt, niczego nie autoryzuje), a jedyną barierą między odwiedzającym a Twoimi danymi są reguły bezpieczeństwa. Każdy produkt ma własne: Firestore, Realtime Database i Storage konfiguruje się osobno, a w aplikacji zwykle otwarte jest to, na co nikt nie spojrzał.
Reguły odpowiadają na pytanie „kto może co"
Reguła dostaje żądanie z uwierzytelnionym użytkownikiem (request.auth), dokument, który ma być odczytany lub zapisany, i nowe dane (request.resource.data). Na tej podstawie decyduje. Kluczowe rozróżnienie to uwierzytelniony (jest sesja) kontra autoryzowany (ta sesja może widzieć ten dokument): request.auth != null sprawdza tylko pierwsze, a rejestracja jest darmowa. Reguły walidują też, co jest zapisywane, żeby użytkownik nie ustawił sobie isAdmin: true we własnym profilu.
Co chroni oprócz reguł
- App Check. Wymaga, żeby żądania pochodziły z Twojej prawdziwej aplikacji (przez reCAPTCHA lub Play Integrity), a nie ze skryptu z Twoim
projectId. Hamuje nadużycia i nieoczekiwane rachunki za masowe odczyty. - Ograniczenie klucza API. W konsoli Google Cloud ogranicz klucz do domen Twojej strony i do API, których używasz. Nie zastępuje reguł, ale zamyka jedne drzwi.
- Auth. Autoryzowane domeny logowania, ochrona przed enumeracją e-maili, weryfikacja e-maila, tylko te metody logowania, których naprawdę używasz, uwierzytelnianie wieloskładnikowe, jeśli przetwarzasz wrażliwe dane.
- Cloud Functions jako serwer. Wszystko, co potrzebuje sekretnego klucza (płatności, e-mail, AI), idzie do funkcji, z sekretem w Secret Manager, a klient wywołuje funkcję. Uwaga: funkcja HTTP jest publiczna dla całego internetu, chyba że sprawdzasz token użytkownika albo używasz funkcji callable z App Check.
- Budżet. Firebase liczy za odczyt i za wywołanie. Alerty budżetowe w Google Cloud i limity w regułach (
request.query.limit) zapobiegają temu, żeby pętla albo atakujący zostawili Ci rachunek.
Hosting: co Firebase ustawia, a czego nie
Firebase Hosting daje automatyczny TLS, CDN i przekierowanie na HTTPS. Nie ustawia nagłówków bezpieczeństwa: dodaje się je w firebase.json. I serwuje wszystko, co jest w katalogu publicznym, łącznie z .env skopiowanym przez pomyłkę.
Część 2: co AI robi źle z Firebase
- Reguły w trybie testowym, a potem
if true. AI zostawia reguły otwierające wszystko na trzydzieści dni; po wygaśnięciu aplikacja pada, a szybkie rozwiązanie to otworzyć je na stałe. request.auth != nulljako jedyny warunek. Każdy zarejestrowany użytkownik czyta dane wszystkich innych.- Zapisy bez walidacji. Profil ma
rolealbocredits, a reguła update nie wyklucza tych pól. - Inne klucze w bundle'u. Obok konfiguracji Firebase pojawia się sekretny klucz Stripe, klucz OpenAI albo klucz usługi mailowej. Szczegóły w sekrety, które Twoja aplikacja wycieka w przeglądarce.
- Funkcje HTTP niesprawdzające użytkownika. Funkcja, która pobiera opłaty, wysyła e-maile albo wywołuje model, odpowiada każdemu, kto zna URL.
- Storage z regułami skopiowanymi z Firestore.
allow read, write: if request.auth != nullwstorage.rules: każdy użytkownik czyta pliki innych i wgrywa, co chce. - Bez App Check, bez nagłówków, bez alertów. Trzy pola, których nikt nie zaznacza, bo aplikacja „już działa".
Blok do wklejenia w projekt
Nagłówki bezpieczeństwa w firebase.json (Content-Security-Policy idzie osobno, bo zależy od Twoich skryptów):
{
"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=()" }
]
}
]
}
}
I punkt wyjścia dla firestore.rules: domyślnie wszystko zamknięte, każdy użytkownik swój dokument, pola uprawnień chronione.
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;
}
}
}
Dodaj potem jawną regułę dla każdej kolekcji; ostatnia, z if false, gwarantuje, że każda nowa kolekcja rodzi się zamknięta.
Prompt do przeglądu przed publikacją
Przejrzyj bezpieczeństwo tej aplikacji z Firebase i na razie niczego nie zmieniaj. Odpowiedz listą:
1. Reguły Firestore, Realtime Database i Storage, które dają dostęp każdemu, z datą trybu testowego albo z request.auth != null jako jedynym warunkiem.
2. Reguły zapisu, które nie walidują pól, zwłaszcza role, isAdmin, plan lub credits.
3. Klucze inne niż konfiguracja Firebase obecne w kodzie przeglądarki, z plikiem i linią.
4. Cloud Functions HTTP, które nie weryfikują tokena użytkownika, oraz funkcje czytające sekrety z kodu zamiast z Secret Manager.
5. Czy App Check jest włączony i czy klucz API jest ograniczony do domen.
6. Nagłówki bezpieczeństwa w firebase.json i pliki w katalogu publicznym, których nie powinno tam być.
Dla każdego punktu zaproponuj dokładną regułę lub zmianę i poczekaj na moje potwierdzenie.
Sprawdź wynik z zewnątrz
Twoje projectId jest w bundle'u, więc każdy może to zrobić. REST API Firestore bez tokena:
curl -s "https://firestore.googleapis.com/v1/projects/TWOJ_PROJEKT/databases/(default)/documents/users" | head -c 400
curl -sI https://twojadomena.com | grep -iE "strict-transport|x-frame|x-content-type"
Prawidłowy wynik to błąd uprawnień w pierwszym (jeśli zwraca dokumenty, kolekcja jest otwarta) i nagłówki w drugim. Powtórz pierwsze dla każdej kolekcji i dla Storage. Scanaris wykonuje te kontrole i około czterdziestu innych w 30 sekund: wykrywa konfigurację Firebase w Twoim bundle'u, odpytuje typowe kolekcje bez uwierzytelnienia, szuka innych kluczy w JavaScripcie, sprawdza nagłówki, CORS, ciasteczka i wystawione pliki, a dla każdego znaleziska daje fix prompt do wklejenia w Lovable, Bolt lub Cursor. Jeśli Twoja aplikacja używa Supabase zamiast Firebase, odpowiednikiem jest przewodnik po Supabase.
Często zadawane pytania
Czy muszę ukrywać apiKey Firebase?
Nie. Jest publiczny z założenia i identyfikuje projekt. Dane chronią reguły i App Check. Warto za to ograniczyć go do Twoich domen w Google Cloud.
Czy Cloud Functions są prywatne?
Funkcja HTTP to publiczny URL. Sprawdzaj token użytkownika wewnątrz funkcji albo używaj funkcji callable z App Check. Funkcje reagujące na zdarzenia (utworzony dokument, wgrany plik) nie mają URL-a i faktycznie są wewnętrzne.
Jak przetestować reguły bez psucia aplikacji?
Symulatorem w konsoli (zakładka Reguły) do testowania konkretnych odczytów i lokalnym emulatorem do testów automatycznych. Zmieniaj reguły z aplikacją otwartą w drugiej karcie i sprawdzaj, czy to, co ma działać, nadal działa.