Unikaj niezabezpieczonych reguł

Z tego przewodnika dowiesz się, jakie są typowe luki w zabezpieczeniach w konfiguracjach Firebase Security Rules, jak sprawdzić i poprawić zabezpieczenia własnych reguł oraz jak przetestować zmiany przed ich wdrożeniem.

Jeśli otrzymasz alert, że Twoje dane nie są odpowiednio zabezpieczone, zapoznaj się z często popełnianymi błędami i zaktualizuj reguły, które są podatne na ataki.

Dostęp do Firebase Security Rules

Aby wyświetlić istniejące Rules, użyj interfejsu wiersza poleceń Firebase lub konsoli Firebase. Aby uniknąć przypadkowego zastąpienia aktualizacji, edytuj reguły, używając tej samej metody. Jeśli nie masz pewności, czy zdefiniowane lokalnie reguły odzwierciedlają najnowsze zmiany, konsola Firebase zawsze pokazuje najnowszą wersję Firebase Security Rules.

Aby uzyskać dostęp do reguł w konsoli Firebase, wybierz swój projekt, a potem przejdź do Realtime Database, Cloud Firestore lub Przechowywanie danych. Gdy znajdziesz się w odpowiedniej bazie danych lub pojemniku magazynu, kliknij Reguły.

Aby uzyskać dostęp do reguł z poziomu wiersza poleceń Firebase, otwórz plik reguł podany w pliku firebase.json.

Firebase Security Rules

Firebase Security Rules chronić dane przed złośliwymi użytkownikami. Podczas tworzenia instancji bazy danych lub zasobnika Cloud Storage w konsoli Firebase możesz odmówić dostępu wszystkim użytkownikom (tryb zablokowany) lub przyznać dostęp wszystkim użytkownikom (tryb testowy). Podczas tworzenia aplikacji możesz chcieć użyć bardziej otwartej konfiguracji, ale pamiętaj, aby przed jej wdrożeniem odpowiednio skonfigurować reguły i zabezpieczyć dane.

Podczas tworzenia aplikacji i testowania różnych konfiguracji reguł możesz użyć jednego z lokalnych emulatorów Firebase, aby uruchomić aplikację w lokalnym środowisku programistycznym.

Typowe scenariusze z regułami, które nie są bezpieczne

Rules, które zostały skonfigurowane domyślnie lub w trakcie tworzenia aplikacji, należy sprawdzić i zaktualizować przed wdrożeniem aplikacji. Upewnij się, że dane użytkowników są odpowiednio zabezpieczone, unikając tych typowych błędów.

Dostęp otwarty

Podczas konfigurowania projektu Firebase mogłeś/mogłaś ustawić reguły, które zezwalają na otwarty dostęp podczas tworzenia. Możesz sądzić, że jesteś jedyną osobą, która korzysta z Twojej aplikacji, ale jeśli ją wdrożysz, jest ona dostępna w internecie. Jeśli nie uwierzytelniasz użytkowników ani nie konfigurujesz reguł zabezpieczeń, każda osoba, która zgadnie identyfikator Twojego projektu, może wykraść, zmodyfikować lub usunąć dane.

Nie zalecane: dostęp do odczytu i zapisu dla wszystkich użytkowników.
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this ruleset in production; it allows
// anyone to overwrite your entire database.

service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if true;
    }
  }
}
{
  // Allow read/write access to all users under any conditions
  // Warning: **NEVER** use this ruleset in production; it allows
  // anyone to overwrite your entire database.

  "rules": {
    ".read": true,
    ".write": true
  }
}
    
// Anyone can read or write to the bucket, even non-users of your app.
// Because it is shared with App Engine, this will also make
// files uploaded using App Engine public.
// Warning: This rule makes every file in your Cloud Storage bucket accessible to any user.
// Apply caution before using it in production, since it means anyone
// can overwrite all your files.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write;
    }
  }
}
    
Rozwiązanie: reguły, które ograniczają dostęp do odczytu i zapisu.

Utwórz reguły, które będą pasować do hierarchii danych. Jednym z najczęstszych rozwiązań tego problemu jest zabezpieczenie oparte na użytkownikach za pomocą Firebase Authentication. Dowiedz się więcej o uwierzytelnianiu użytkowników za pomocą reguł.

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow only authenticated content owners access
    match /some_collection/{document} {
      // Allow reads and deletion if the current user owns the existing document
      allow read, delete: if request.auth.uid == resource.data.author_uid;
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;

    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      // Allow public reads
      allow read: if true
      // Allow creation if the current user owns the new document
      allow create: if request.auth.uid == request.resource.data.author_uid;
      // Allow updates by the owner, and prevent change of ownership
      allow update: if request.auth.uid == request.resource.data.author_uid
                    && request.auth.uid == resource.data.author_uid;
      // Allow deletion if the current user owns the existing document
      allow delete: if request.auth.uid == resource.data.author_uid;
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

Dostęp dla każdego uwierzytelnionego użytkownika

Czasami Rules sprawdza, czy użytkownik jest zalogowany, ale nie ogranicza dostępu na podstawie uwierzytelnienia. Jeśli jedna z Twoich reguł zawiera element auth != null, potwierdź, że chcesz, aby każdy zalogowany użytkownik miał dostęp do danych.

Niezalecane: każdy zalogowany użytkownik ma dostęp do odczytu i edycji całej bazy danych.
service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow read, write: if request.auth.uid != null;
    }
  }
}
{
  "rules": {
    ".read": "auth.uid !== null",
    ".write": "auth.uid !== null"
  }
}
// Only authenticated users can read or write to the bucket
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if request.auth != null;
    }
  }
}
Rozwiązanie: ogranicz dostęp za pomocą warunków zabezpieczeń.

Podczas sprawdzania uwierzytelniania możesz też użyć jednej z właściwości uwierzytelniania, aby dodatkowo ograniczyć dostęp do określonych zbiorów danych dla konkretnych użytkowników. Dowiedz się więcej o różnych właściwościach uwierzytelniania.

service cloud.firestore {
  match /databases/{database}/documents {
    // Assign roles to all users and refine access based on user roles
    match /some_collection/{document} {
     allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader"
     allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"

     // Note: Checking for roles in your database using `get` (as in the code
     // above) or `exists` carry standard charges for read operations.
    }
  }
}
// Give each user in your database a particular attribute
// and set it to true/false
// Then, use that attribute to grant access to subsets of data
// For example, an "administrator" attribute set
// to "true" grants write access to data

service cloud.firestore {
  match /databases/{database}/documents {
    match /some_collection/{document} {
      allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
      allow read: true;
    }
  }
}
  
service cloud.firestore {
  match /databases/{database}/documents {
    // Allow public read access, but only content owners can write
    match /some_collection/{document} {
      allow read: if true
      allow write: if request.auth.uid == request.resource.data.author_uid
    }
  }
}
  
{
  "rules": {
    "some_path": {
      "$uid": {
        // Allow only authenticated content owners access to their data
        ".read": "auth.uid === $uid",
        ".write": "auth.uid === $uid"
      }
    }
  }
}
    
{
  "rules": {
    "some_path/$uid": {
      ".write": "auth.uid === $uid",
      // Create a "public" subpath in your dataset
      "public": {
        ".read": true
        // or ".read": "auth.uid !== null"
      },
      // Create a "private" subpath in your dataset
      "private": {
        ".read": "auth.uid === $uid"
      }
    }
  }
}
    
{
  // Allow anyone to read data, but only authenticated content owners can
  // make changes to their data

  "rules": {
    "some_path/$uid": {
      ".read": true,
      // or ".read": "auth.uid !== null" for only authenticated users
      ".write": "auth.uid === $uid"
    }
  }
}
    
// Allow reads if the group ID in your token matches the file metadata `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
  allow read: if resource.metadata.owner == request.auth.token.groupId;
  allow write: if request.auth.token.groupId == groupId;
}
// Grants a user access to a node matching their user ID
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read, write: if request.auth.uid == userId;
    }
  }
}
service firebase.storage {
  match /b/{bucket}/o {
    // Files look like: "user/<UID>/file.txt"
    match /user/{userId}/{fileName} {
      allow read;
      allow write: if request.auth.uid == userId;
    }
  }
}
  

(Realtime Database) Nieprawidłowo odziedziczone reguły

Realtime Database Security Rules kaskadowo, przy czym reguły na krótszych ścieżkach nadrzędnych zastępują reguły na dłuższych ścieżkach podrzędnych. Podczas tworzenia reguły w węźle podrzędnym pamiętaj, że może ona przyznawać tylko dodatkowe uprawnienia. Nie możesz zawęzić ani cofnąć dostępu do danych na niższym poziomie w bazie danych.

Niezalecane: dopracowywanie reguł na ścieżkach podrzędnych
{
  "rules": {
     "foo": {
        // allows read to /foo/*
        ".read": "data.child('baz').val() === true",
        "bar": {
          /* ignored, since read was allowed already */
          ".read": false
        }
     }
  }
}
Rozwiązanie: na ścieżkach nadrzędnych zapisz reguły o szerokim zakresie, a na ścieżkach podrzędnych nadaj bardziej szczegółowe uprawnienia. Jeśli Twoje potrzeby dotyczące dostępu do danych wymagają większej szczegółowości, zachowaj szczegółowość reguł. Dowiedz się więcej o umieszczaniu Realtime Database Security Rules w poziomie w podstawowej składni Realtime Database Security Rules.

Dostęp zamknięty

Podczas tworzenia aplikacji możesz też zablokować swoje dane. Zwykle oznacza to, że dostęp do odczytu i zapisu został zamknięty dla wszystkich użytkowników w następujący sposób:

// Deny read/write access to all users under any conditions
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
  }
}
{
  "rules": {
    ".read": false,
    ".write": false
  }
}
    
// Access to files through Cloud Storage is completely disallowed.
// Files may still be accessible through App Engine or Google Cloud Storage APIs.

service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
      allow read, write: if false;
    }
  }
}

Pakiety SDK Firebase Admin i Cloud Functions nadal mają dostęp do Twojej bazy danych. Używaj tych reguł, gdy chcesz używać pakietu Cloud Firestore lub Realtime Database jako backendu tylko na serwerze w połączeniu z pakietem Firebase Admin SDK. Mimo że jest to bezpieczne, sprawdź, czy klienci aplikacji mogą prawidłowo pobierać dane.

Dowiedz się więcej o Cloud Firestore Security Rules i o tym, jak działają te funkcje, z artykułu Początkujący: korzystanie z Cloud Firestore Security Rules.

Testowanie Cloud Firestore Security Rules

Aby sprawdzić działanie aplikacji i sprawdzać konfiguracje Cloud Firestore Security Rules, użyj emulatora Firebase. Przed wdrożeniem zmian użyj emulatora Cloud Firestore do uruchamiania i automatyzacji testów jednostkowych w środowisku lokalnym.

Aby szybko zweryfikować Firebase Security Rules w konsoli Firebase, użyj symulatora reguł Firebase.