---
title: "Firebase security rules eksempler: 11 regler jeg angrep"
description: "Firebase security rules eksempler testet i emulatoren. Hva hver regel lot en gjest eller bruker gjøre, hvilke lekkasjer som ble igjen og regelen som lukket dem."
url: "https://madsalt.tech/no/blog/firebase-security-rules-examples/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/no/about/"
language: "no"
published: 2026-11-03
---

# Firebase security rules eksempler: 11 regler jeg angrep

TL;DR

Jeg sendte de samme forespørslene mot 11 Firestore-regelsett som gjest, anonym bruker og tre innloggede brukere. `request.auth != null` lot en fremmed lese, endre og slette alles ordrer. En eiersjekk kun på `resource` lot en bruker gi en ordre til en annen. Ett bredt `{document=**}`-match åpnet en samling som hadde en riktig eierregel. Og en rolle lagret i et dokument brukeren kan skrive, gjorde dem til admin i én forespørsel. Hver av dem har en løsning under, og den rettede regelen holdt mot de samme forespørslene.

I en Firebase-app finnes det ingen server av deg mellom nettleseren og databasen. Prosjektkonfigurasjonen følger med siden, og [security rules](https://firebase.google.com/docs/rules/insecure-rules) er det eneste som står mellom alle som har den og dataene dine. Derfor ville jeg ha eksempler på regler med angrepet ved siden av, ikke en liste over regler som bare ser riktige ut.

**Slik testet jeg.** Firebase Local Emulator Suite fra Firebase CLI 15.34.2, 3. november 2026. Jeg lastet hvert regelsett, nullstilte dataene og kalte Firestore REST API med ekte tokens fra Auth-emulatoren: uten token, en anonym bruker, brukerne A og B og en fremmed som bare hadde registrert seg. Dataene var oppdiktede: ordrene `a1` og `a2` eies av A, `b1` eies av B.

## Hvilke Firebase-regler lekker?

| Regel                                   | Forespørsel                            | Resultat      |
| --------------------------------------- | -------------------------------------- | ------------- |
| `if true` (testmodus)                   | Gjest lister ordrer                    | `200`, alle 3 |
| `if true` (testmodus)                   | Gjest sletter Bs ordre                 | `200`         |
| `request.auth != null`                  | Anonym bruker lister ordrer            | `200`, alle 3 |
| `request.auth != null`                  | Fremmed sletter As ordre               | `200`         |
| Eiersjekk kun på `resource`             | A oppretter en ordre eid av B          | `200`         |
| Eiersjekk kun på `resource`             | A endrer `ownerId` på egen ordre       | `200`         |
| Eierregel pluss `{document=**}` read    | A leser Bs ordre                       | `200`         |
| Bruker kan skrive eget `users`-dokument | A setter `role: admin`, leser Bs ordre | `200`         |

## Hva åpner testmodus egentlig?

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

Alt, for alle. En gjest uten token listet alle 3 ordrene, slettet én og opprettet en ny. Ingenting av dette krever en konto eller en lekket hemmelighet, bare prosjekt-ID-en.

Den daterte versjonen som testmodus ofte bruker, feiler på en annen måte. Med `if request.time < timestamp.date(2026, 1, 1)` og den datoen i fortiden fikk gjesten `403`, og det samme fikk bruker A som leste sin egen ordre. Lekkasjen er over, og det er appen også.

## Er `request.auth != null` nok?

Nei. Den sier bare at forespørselen har en konto bak seg.

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

Gjesten fikk `403`, og det er derfor regelen føles trygg i en rask test. Så listet en fremmed som bare hadde registrert seg alle 3 ordrene, endret totalen på Bs ordre og slettet As ordre, alt med `200`. En anonym bruker listet også alle 3. Hvis registreringen er åpen, betyr denne regelen «alle som gidder å registrere seg». Firebase-dokumentasjonen nevner den også som et [vanlig usikkert mønster](https://firebase.google.com/docs/rules/insecure-rules).

## Hvorfor trenger en eiersjekk både `resource` og `request.resource`?

`resource` er dokumentet slik det er lagret. `request.resource` er dokumentet slik det ville vært etter skrivingen. En regel som bare ser på det første, sjekker hvem som eier raden nå, og sier ingenting om hva de gjør den til.

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

Lesing så riktig ut: A fikk `200` på sin egen ordre og `403` på Bs. Skriving gjorde det ikke. A opprettet en ny ordre med `ownerId` satt til B og fikk `200`. Deretter endret A `ownerId` på sin egen ordre til B, også `200`, og B kunne lese den fra da av. I en app der ordrer betyr fakturaer eller saldoer er det en bruker som skriver inn på en annens konto.

Denne versjonen avviste alt:

```
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;
}
```

| Forespørsel fra A            | Resultat |
| ---------------------------- | -------- |
| Lese egen ordre              | `200`    |
| Lese, endre, slette Bs ordre | `403`    |
| Opprette en ordre eid av B   | `403`    |
| Endre `ownerId` til B        | `403`    |

Den lot likevel A endre `total` på sin egen ordre, med `200`. Hvis klienten ikke skal sette det feltet, si hvilke felt den får endre:

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

Med denne ga endring av `total` `403`, og endring av `note` ga `200`.

## Hvorfor feilet spørringen min med en riktig regel?

Fordi [regler ikke er filtre](https://firebase.google.com/docs/firestore/security/rules-query). Under eierregelen over fikk A `403` da den ba om hele samlingen, selv om A eier 2 av de 3 ordrene. Firestore vurderer spørringen etter hva den kunne returnere, ikke etter hva som faktisk finnes.

| Forespørsel fra A       | Resultat      |
| ----------------------- | ------------- |
| List alle ordrer        | `403`         |
| Spørring `ownerId == A` | `200`, 2 dok. |
| Spørring `ownerId == B` | `403`         |

Så når en liste slutter å virke etter at du har strammet inn reglene, fiks spørringen. Å løsne regelen for at listen skal virke er slik de brede reglene over blir skrevet.

## Kan et bredt match oppheve en riktig regel?

Ja, og det er den jeg ville lett etter først i et prosjekt med en lang regelfil. Firestore [tillater en forespørsel hvis en av de matchende reglene tillater den](https://firebase.google.com/docs/firestore/security/rules-structure).

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

Den første blokken ser ut som en god eierregel. Med den andre blokken til stede leste A Bs ordre med `200`, en fremmed listet alle 3 ordrene, og den samme fremmede leste As dokument i `users`. Ingenting i den første blokken advarer deg. Slett det brede matchet; det finnes ingen måte å få en senere regel til å ta tilbake tilgang.

## Hvordan gjør en bruker seg selv til admin?

Dette mønsteret dukker opp når roller ligger i et 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();
}
```

«Brukere kan redigere sin egen profil» og «admins kan lese alle ordrer» er hver for seg fornuftige. Sammen er de en privilegieeskalering.

![Admin i én forespørsel. Bruker A, hvis eget users-dokument kan skrives. Før: Bruker A → leser Bs ordre → 403; Skriv egen rolle: Bruker A → role: admin → 200; Etter: Bruker A → leser Bs ordre → 200.](https://madsalt.tech/charts/no/firebase-security-rules-examples.svg)

*Figur 1. Testen min i Firebase-emulatoren (CLI 15.34.2), 3. november 2026.*

Løsningen er å hindre klienten i å skrive det feltet. Med `request.resource.data.role == resource.data.role` lagt til skrivereglen ga den samme forespørselen `403`, og A holdt seg utenfor Bs ordre. Custom claims satt fra en server er den andre veien, siden en klient ikke kan endre dem.

## To ting som viste seg å være greie

Regler på en forelder lekker ikke ned i subsamlinger. Med `allow read` på `/orders/{id}` for enhver innlogget bruker leste A ordren, og `/orders/b1/notes/n1` under den ga `403`. Det er [dokumentert oppførsel](https://firebase.google.com/docs/firestore/security/rules-structure): regler gjelder bare på den matchede stien.

En gjest slipper ikke gjennom en sammenligning med manglende token. `resource.data.ownerId == request.auth.uid` ga `403` for gjesten selv uten en egen `request.auth != null`. Jeg skriver sjekken ut likevel, fordi regelen da sier det den mener.

## Hvordan sjekker du dine egne regler?

Kjør forespørslene dine i emulatoren som gjest, som fremmed og som en andre bruker. Det var det som avslørte hvert tilfelle over; å lese reglene gjorde det ikke.

For en første gjennomgang leser den gratis [Firebase regelsjekk](https://madsalt.tech/no/tools/firebase-rules-checker/) limte inn regler uten å røre prosjektet ditt. På regelsettene her flagget den testmodus, tilgang kun for innloggede, det brede matchet og den selvskrevne rollen. Den leser bare tekst, så den kan ikke si hva dataene dine ser ut som eller om en regel ble deployet.

`apiKey` på siden din er ikke problemet i seg selv. Firebase web-konfigurasjon er offentlig av design, og den gratis [Secret scanner](https://madsalt.tech/no/tools/secret-scanner/) markerer den slik, fordi det er reglene som beskytter dataene bak. Filer følger igjen andre regler, med en lekkasje reglene ikke kan stoppe, som jeg testet i Firebase Storage rules.

**Begrensninger.** Bare Firestore, i den lokale emulatoren, over REST, på oppdiktede data. Realtime Database bruker et annet regelspråk og ble ikke testet. App Check, som begrenser hvilke apper som kan kalle backenden din, er ikke med her; det erstatter ikke regler. Produksjon kan avvike fra emulatoren i detaljer jeg ikke sjekket.

Usikker på hva reglene dine slipper gjennom?

Jeg leser dem gjerne sammen med deg. Ingen salgstale.

[Ta kontakt](https://madsalt.tech/no/#contact)
