Hoppa till innehållet

Firebase säkerhetsregler: 11 exempel jag attackerade

Visa som MarkdownÖppna i ClaudeÖppna i ChatGPTÖppna i Perplexity

Frågan kopieras också. Om chatten öppnas tom, klistra in den.

Kort sagt

Jag skickade samma förfrågningar mot 11 Firestore-regeluppsättningar som gäst, som anonym användare och som tre inloggade användare. request.auth != null lät en främling läsa, ändra och radera allas ordrar. En ägarkontroll enbart på resource lät en användare lämna över en order till någon annan. Ett enda brett {document=**}-match öppnade en samling som hade en korrekt ägarregel. Och en roll lagrad i ett dokument som användaren kan skriva till gjorde hen till admin i en enda förfrågan. Varje fall har en rättning nedan, och den rättade regeln höll mot samma förfrågningar.

En Firebase-app har ingen server av dig mellan webbläsaren och databasen. Projektets konfiguration följer med sidan, och säkerhetsreglerna är det som står mellan den som har den och dina data. Så jag ville ha regelexempel med attacken bredvid, inte en lista med regler som ser rätt ut.

Så testade jag. Firebase Local Emulator Suite från Firebase CLI 15.34.2, den 3 november 2026. Jag laddade varje regeluppsättning, återställde data och anropade Firestores REST-API med riktiga tokens från Auth-emulatorn: ingen token, en anonym användare, användarna A och B och en främling som bara registrerat sig. Datan var påhittad: ordrarna a1 och a2 ägs av A, b1 av B.

Vilka Firebase-regler läcker?

Regel Förfrågan Resultat
if true (testläge) Gäst listar ordrarna 200, alla 3
if true (testläge) Gäst raderar Bs order 200
request.auth != null Anonym användare listar ordrarna 200, alla 3
request.auth != null Främling raderar As order 200
Ägarkontroll enbart på resource A skapar en order som ägs av B 200
Ägarkontroll enbart på resource A ändrar ownerId på sin egen order 200
Ägarregel plus läsning på {document=**} A läser Bs order 200
Användaren kan skriva sitt eget users-dok A sätter role: admin, läser Bs order 200

Vad öppnar testläget egentligen?

match /{document=**} {
  allow read, write: if true;
}

Allt, för alla. En gäst utan token listade alla 3 ordrar, raderade en och skapade en ny. Inget av det kräver ett konto eller en läckt hemlighet, bara projekt-id:t.

Den daterade varianten som testläget ofta använder felar på ett annat sätt. Med if request.time < timestamp.date(2026, 1, 1) och det datumet i det förflutna fick gästen 403, och det fick också användare A när hen läste sin egen order. Läckan är över, och det är appen också.

Räcker request.auth != null?

Nej. Det säger bara att förfrågan har något konto bakom sig.

match /orders/{id} {
  allow read, write: if request.auth != null;
}

Gästen fick 403, vilket är varför regeln känns säker i ett snabbt test. Sedan listade en främling som bara registrerat sig alla 3 ordrar, ändrade totalen på Bs order och raderade As order, allt med 200. En anonym användare listade alla 3 också. Om registreringen är öppen betyder regeln “alla som orkar registrera sig”. Firebase-dokumentationen listar den också som ett vanligt osäkert mönster.

Varför behöver en ägarkontroll både resource och request.resource?

resource är dokumentet som det är lagrat. request.resource är dokumentet som det skulle bli efter skrivningen. En regel som bara tittar på det första kontrollerar vem som äger raden nu, och säger ingenting om vad de gör den till.

match /orders/{id} {
  allow read, update, delete: if resource.data.ownerId == request.auth.uid;
  allow create: if request.auth != null;
}

Läsningarna såg rätt ut: A fick 200 på sin egen order och 403 på Bs. Skrivningarna gjorde det inte. A skapade en ny order med ownerId satt till B och fick 200. Sedan ändrade A ownerId på sin egen order till B, också 200, och B kunde läsa den från och med då. I en app där ordrar är fakturor eller saldon är det en användare som skriver in sig i någon annans konto.

Den här versionen avvisade allt:

match /orders/{id} {
  allow read, delete: if request.auth != null
    && resource.data.ownerId == request.auth.uid;
  allow create: if request.auth != null
    && request.resource.data.ownerId == request.auth.uid;
  allow update: if request.auth != null
    && resource.data.ownerId == request.auth.uid
    && request.resource.data.ownerId == resource.data.ownerId;
}
Förfrågan från A Resultat
Läsa egen order 200
Läsa, uppdatera, radera Bs order 403
Skapa en order som ägs av B 403
Ändra ownerId till B 403

Den lät fortfarande A ändra total på sin egen order, med 200. Om klienten inte ska sätta det fältet, ange vilka fält den får ändra:

allow update: if request.auth != null
  && resource.data.ownerId == request.auth.uid
  && request.resource.data.diff(resource.data).affectedKeys().hasOnly(['note']);

Med detta gav ändring av total 403 och ändring av note gav 200.

Varför misslyckades min fråga med en korrekt regel?

För att regler inte är filter. Under ägarregeln ovan fick A 403 när hen bad om hela samlingen, fast A äger 2 av de 3 ordrarna. Firestore bedömer frågan efter vad den skulle kunna returnera, inte efter vad som finns.

Förfrågan från A Resultat
Lista alla ordrar 403
Fråga ownerId == A 200, 2 docs
Fråga ownerId == B 403

Så när en lista slutar fungera efter att du skärpt reglerna, rätta frågan. Att lätta på regeln för att få listan att fungera är hur de breda reglerna ovan skrivs.

Kan ett brett match ta ut en korrekt regel?

Ja, och det här är det jag skulle leta efter först i ett projekt med en lång regelfil. Firestore tillåter en förfrågan om någon matchande regel tillåter den.

match /orders/{id} {
  allow read: if request.auth != null
    && resource.data.ownerId == request.auth.uid;
}
match /{document=**} {
  allow read: if request.auth != null;
}

Det första blocket ser ut som en bra ägarregel. Med det andra blocket på plats läste A Bs order med 200, en främling listade alla 3 ordrar och samma främling läste As dokument i users. Ingenting i det första blocket varnar. Radera det breda matchet; det går inte att få en senare regel att ta tillbaka åtkomst.

Hur gör en användare sig själv till admin?

Det här mönstret dyker upp så fort roller ligger i ett dokument:

function isAdmin() {
  return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}
match /users/{uid} {
  allow read, write: if request.auth.uid == uid;
}
match /orders/{id} {
  allow read: if resource.data.ownerId == request.auth.uid || isAdmin();
}

“Användare kan redigera sin egen profil” och “admins kan läsa alla ordrar” är var för sig rimliga. Tillsammans är de en privilegieeskalering.

Admin i en enda förfrågan. Användare A, vars eget users-dokument går att skriva till. Före: Användare A → läs Bs order → 403; Skriv egen roll: Användare A → role: admin → 200; Efter: Användare A → läs Bs order → 200.
Figur 1. Mitt test i Firebase-emulatorn (CLI 15.34.2), 3 november 2026.

Rättningen är att hindra klienten från att skriva det fältet. Med request.resource.data.role == resource.data.role tillagt i skrivregeln gav samma förfrågan 403 och A höll sig utanför Bs order. Custom claims som sätts från en server är den andra vägen, eftersom en klient inte kan ändra dem.

Två saker som visade sig vara i sin ordning

Regler på en förälder läcker inte ner i underkollektioner. Med allow read på /orders/{id} för alla inloggade användare läste A ordern, och /orders/b1/notes/n1 under den gav 403. Det är det dokumenterade beteendet: regler gäller bara på den matchade sökvägen.

En gäst slinker inte igenom en jämförelse med en saknad token. resource.data.ownerId == request.auth.uid gav gästen 403 även utan en separat request.auth != null. Jag skriver ändå ut kontrollen, eftersom regeln då säger vad den menar.

Hur kontrollerar du dina egna regler?

Kör dina förfrågningar i emulatorn som gäst, som främling och som andra användare. Det var det som avslöjade varje fall ovan; att läsa reglerna gjorde det inte.

För en första genomgång läser den gratis Firebase regelkontroll inklistrade regler utan att röra ditt projekt. På regeluppsättningarna här flaggade den testläget, åtkomst enbart för inloggade, det breda matchet och den självskrivna rollen. Den läser bara text, så den kan inte säga hur din data ser ut eller om en regel har driftsatts.

Din apiKey på sidan är inte problemet i sig. Firebase webbkonfiguration är offentlig av design, och den gratis Secret scanner markerar den så, eftersom det är reglerna som skyddar datan bakom den. Filer följer återigen andra regler, med en läcka som reglerna inte stoppar, och den testade jag i Firebase Storage-regler.

Begränsningar. Bara Firestore, i den lokala emulatorn, över REST, på påhittad data. Realtime Database använder ett annat regelspråk och testades inte. App Check, som begränsar vilka appar som får anropa din backend, ingår inte; det ersätter inte regler. Produktion kan skilja sig från emulatorn i detaljer jag inte kontrollerade.

Osäker på vad dina regler släpper igenom?

Jag läser dem gärna tillsammans med dig. Ingen säljpitch.

Hör av dig

© 2026 Denys Zaichenko. Originalartikel: https://madsalt.tech/sv/blog/firebase-security-rules-examples/