---
title: "Firebase Security Rules Beispiele: 11 angegriffene Regeln"
description: "Firebase Security Rules im Emulator getestet. Was jede Regel einem Gast oder Nutzer erlaubte, welche Lecks offen blieben und welche Regel sie schloss."
url: "https://madsalt.tech/de/blog/firebase-security-rules-examples/"
author: "Denys Zaichenko"
author_url: "https://madsalt.tech/de/about/"
language: "de"
published: 2026-11-03
---

# Firebase Security Rules Beispiele: 11 angegriffene Regeln

TL;DR

Ich habe dieselben Anfragen gegen 11 Firestore-Regelsätze geschickt, als Gast, als anonymer Nutzer und als drei angemeldete Nutzer. `request.auth != null` ließ einen Fremden die Bestellungen aller lesen, ändern und löschen. Eine Besitzerprüfung allein auf `resource` ließ einen Nutzer eine Bestellung an jemand anderen übergeben. Ein breites `{document=**}`-Match öffnete eine Collection, die eine korrekte Besitzerregel hatte. Und eine Rolle in einem Dokument, das der Nutzer selbst schreiben darf, machte ihn mit einer Anfrage zum Admin. Zu jedem Fall gibt es unten eine Korrektur, und die korrigierte Regel hielt gegen dieselben Anfragen.

Zwischen Browser und Datenbank einer Firebase-App sitzt kein Server von Ihnen. Die Projektkonfiguration steckt in der Seite, und [Security Rules](https://firebase.google.com/docs/rules/insecure-rules) sind das Einzige, was jeden, der sie hat, von Ihren Daten trennt. Deshalb wollte ich Beispiele für Regeln mit dem Angriff daneben, keine Liste von Regeln, die nur richtig aussehen.

**So habe ich getestet.** Firebase Local Emulator Suite aus Firebase CLI 15.34.2, am 3. November 2026. Ich habe jeden Regelsatz geladen, die Daten zurückgesetzt und die Firestore-REST-API mit echten Tokens aus dem Auth-Emulator aufgerufen: ohne Token, ein anonymer Nutzer, die Nutzer A und B und ein Fremder, der sich nur registriert hatte. Die Daten waren ausgedacht: Die Bestellungen `a1` und `a2` gehören A, `b1` gehört B.

## Welche Firebase-Regeln lecken?

| Regel                                          | Anfrage                                    | Ergebnis      |
| ---------------------------------------------- | ------------------------------------------ | ------------- |
| `if true` (Testmodus)                          | Gast listet Bestellungen                   | `200`, alle 3 |
| `if true` (Testmodus)                          | Gast löscht Bs Bestellung                  | `200`         |
| `request.auth != null`                         | Anonymer Nutzer listet Bestellungen        | `200`, alle 3 |
| `request.auth != null`                         | Fremder löscht As Bestellung               | `200`         |
| Besitzerprüfung nur auf `resource`             | A legt eine Bestellung von B an            | `200`         |
| Besitzerprüfung nur auf `resource`             | A ändert `ownerId` der eigenen Bestellung  | `200`         |
| Besitzerregel plus Lesen auf `{document=**}`   | A liest Bs Bestellung                      | `200`         |
| Nutzer darf eigenes `users`-Dokument schreiben | A setzt `role: admin`, liest Bs Bestellung | `200`         |

## Was öffnet der Testmodus eigentlich?

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

Alles, für alle. Ein Gast ohne Token listete alle 3 Bestellungen, löschte eine und legte eine neue an. Dafür braucht es weder ein Konto noch ein geleaktes Geheimnis, nur die Projekt-ID.

Die datierte Variante, die der Testmodus oft verwendet, scheitert anders. Mit `if request.time < timestamp.date(2026, 1, 1)` und einem Datum in der Vergangenheit bekam der Gast `403`, ebenso Nutzer A beim Lesen der eigenen Bestellung. Das Leck ist weg, und die App gleich mit.

## Reicht `request.auth != null`?

Nein. Es sagt nur, dass hinter der Anfrage irgendein Konto steht.

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

Der Gast bekam `403`, deshalb wirkt diese Regel im schnellen Test sicher. Dann listete ein Fremder, der sich nur registriert hatte, alle 3 Bestellungen, änderte die Summe von Bs Bestellung und löschte As Bestellung, jeweils mit `200`. Ein anonymer Nutzer listete ebenfalls alle 3. Wenn die Registrierung offen ist, heißt diese Regel „jeder, der sich die Mühe macht“. Die Firebase-Dokumentation führt sie auch als [häufiges unsicheres Muster](https://firebase.google.com/docs/rules/insecure-rules).

## Warum braucht eine Besitzerprüfung `resource` und `request.resource`?

`resource` ist das Dokument, wie es gespeichert ist. `request.resource` ist das Dokument, wie es nach dem Schreiben aussähe. Eine Regel, die nur das erste prüft, prüft, wem die Zeile jetzt gehört, und sagt nichts darüber, was daraus gemacht wird.

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

Das Lesen sah richtig aus: A bekam `200` auf die eigene Bestellung und `403` auf Bs. Das Schreiben nicht. A legte eine neue Bestellung mit `ownerId` auf B an und bekam `200`. Dann änderte A `ownerId` der eigenen Bestellung auf B, ebenfalls `200`, und B konnte sie von da an lesen. In einer App, in der Bestellungen Rechnungen oder Salden bedeuten, schreibt damit ein Nutzer in das Konto eines anderen.

Diese Fassung lehnte alles ab:

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

| Anfrage von A                        | Ergebnis |
| ------------------------------------ | -------- |
| Eigene Bestellung lesen              | `200`    |
| Bs Bestellung lesen, ändern, löschen | `403`    |
| Bestellung von B anlegen             | `403`    |
| `ownerId` auf B ändern               | `403`    |

Sie ließ A aber weiterhin `total` der eigenen Bestellung ändern, mit `200`. Wenn der Client dieses Feld nicht setzen darf, nennen Sie die Felder, die er ändern darf:

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

Damit gab eine Änderung von `total` `403` zurück und eine Änderung von `note` `200`.

## Warum scheiterte meine Abfrage trotz korrekter Regel?

Weil [Regeln keine Filter sind](https://firebase.google.com/docs/firestore/security/rules-query). Unter der Besitzerregel oben bekam A auf die Abfrage der ganzen Collection `403`, obwohl A 2 der 3 Bestellungen gehören. Firestore beurteilt die Abfrage danach, was sie zurückgeben könnte, nicht danach, was vorhanden ist.

| Anfrage von A            | Ergebnis      |
| ------------------------ | ------------- |
| Alle Bestellungen listen | `403`         |
| Abfrage `ownerId == A`   | `200`, 2 Dok. |
| Abfrage `ownerId == B`   | `403`         |

Wenn eine Liste nach dem Verschärfen der Regeln kaputtgeht, korrigieren Sie also die Abfrage. Die Regel zu lockern, damit die Liste funktioniert, ist genau der Weg, auf dem die breiten Regeln oben entstehen.

## Kann ein breites Match eine korrekte Regel aufheben?

Ja, und danach würde ich in einem Projekt mit langer Regeldatei zuerst suchen. Firestore [erlaubt eine Anfrage, wenn irgendeine passende Regel sie erlaubt](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;
}
```

Der erste Block liest sich wie eine gute Besitzerregel. Mit dem zweiten Block las A Bs Bestellung mit `200`, ein Fremder listete alle 3 Bestellungen, und derselbe Fremde las As Dokument in `users`. Nichts im ersten Block warnt Sie. Löschen Sie das breite Match; eine spätere Regel kann Zugriff nicht wieder entziehen.

## Wie macht sich ein Nutzer selbst zum Admin?

Dieses Muster taucht auf, sobald Rollen in einem Dokument liegen:

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

„Nutzer dürfen ihr eigenes Profil bearbeiten“ und „Admins dürfen alle Bestellungen lesen“ sind jeweils vernünftig. Zusammen sind sie eine Rechteausweitung.

![Admin mit einer Anfrage. Nutzer A, dessen eigenes users-Dokument schreibbar ist. Vorher: Nutzer A → liest Bs Bestellung → 403; Eigene Rolle schreiben: Nutzer A → role: admin → 200; Nachher: Nutzer A → liest Bs Bestellung → 200.](https://madsalt.tech/charts/de/firebase-security-rules-examples.svg)

*Abbildung 1. Mein Test im Firebase-Emulator (CLI 15.34.2), 3. November 2026.*

Die Lösung: den Client daran hindern, dieses Feld zu schreiben. Mit `request.resource.data.role == resource.data.role` in der Schreibregel gab dieselbe Anfrage `403` zurück, und A blieb aus Bs Bestellung draußen. Custom Claims, die von einem Server gesetzt werden, sind der andere Weg, denn ein Client kann sie nicht ändern.

## Zwei Dinge, die sich als in Ordnung herausstellten

Regeln auf einem übergeordneten Pfad lecken nicht in Subcollections. Mit `allow read` auf `/orders/{id}` für jeden angemeldeten Nutzer las A die Bestellung, und `/orders/b1/notes/n1` darunter gab `403`. Das ist das [dokumentierte Verhalten](https://firebase.google.com/docs/firestore/security/rules-structure): Regeln gelten nur am passenden Pfad.

Ein Gast kommt nicht durch einen Vergleich mit einem fehlenden Token. `resource.data.ownerId == request.auth.uid` gab dem Gast `403`, auch ohne separates `request.auth != null`. Ich schreibe die Prüfung trotzdem hin, weil die Regel dann sagt, was sie meint.

## Wie prüfen Sie Ihre eigenen Regeln?

Führen Sie Ihre Anfragen im Emulator als Gast, als Fremder und als zweiter Nutzer aus. Das hat jeden Fall oben aufgedeckt; das Lesen der Regeln nicht.

Für einen ersten Durchgang liest der kostenlose [Firebase-Regelcheck](https://madsalt.tech/de/tools/firebase-rules-checker/) eingefügte Regeln, ohne Ihr Projekt anzufassen. Bei den Regelsätzen hier markierte er den Testmodus, Zugriff nur mit Anmeldung, das breite Match und die selbst geschriebene Rolle. Er liest nur Text, kann also nicht sagen, wie Ihre Daten aussehen oder ob eine Regel ausgerollt wurde.

Ihr `apiKey` in der Seite ist für sich kein Problem. Die Firebase-Webkonfiguration ist absichtlich öffentlich, und der kostenlose [Secret-Scanner](https://madsalt.tech/de/tools/secret-scanner/) kennzeichnet sie so, denn die Regeln schützen die Daten dahinter. Für Dateien gelten wiederum andere Regeln, mit einem Leck, das Regeln nicht stoppen können, und das habe ich in Firebase-Storage-Regeln getestet.

**Grenzen.** Nur Firestore, im lokalen Emulator, über REST, mit ausgedachten Daten. Die Realtime Database nutzt eine andere Regelsprache und wurde nicht getestet. App Check, das einschränkt, welche Apps Ihr Backend aufrufen dürfen, gehört nicht dazu; es ersetzt keine Regeln. Die Produktion kann sich vom Emulator in Details unterscheiden, die ich nicht geprüft habe.

Unsicher, was Ihre Regeln durchlassen?

Gern lese ich sie mit Ihnen. Ohne Verkaufsgespräch.

[Kontakt aufnehmen](https://madsalt.tech/de/#contact)
