Walidacja danych

Możesz używać Firebase Security Rules, aby warunkowo zapisywać nowe dane na podstawie istniejących danych w bazie danych lub zasobniku pamięci. Możesz też pisać reguły, które wymuszają weryfikację danych, ograniczając zapisywanie na podstawie nowych danych. Czytaj dalej, aby dowiedzieć się więcej o regułach, które wykorzystują istniejące dane do tworzenia warunków bezpieczeństwa.

Wybierz usługę w każdej sekcji, aby dowiedzieć się więcej o regułach weryfikacji danych.

Ograniczenia dotyczące nowych danych

Cloud Firestore

Jeśli chcesz mieć pewność, że dokument zawierający określone pole nie zostanie utworzony, możesz uwzględnić to pole w warunku allow. Jeśli na przykład chcesz zabronić tworzenia dokumentów zawierających pole ranking, musisz to zrobić w warunku create.

  service cloud.firestore {
    match /databases/{database}/documents {
      // Disallow
      match /cities/{city} {
        allow create: if !("ranking" in request.resource.data)
      }
    }
  }

Realtime Database

Jeśli chcesz mieć pewność, że dane zawierające określone wartości nie zostaną dodane do bazy danych, uwzględnij tę wartość w regułach i zablokuj zapisywanie. Jeśli na przykład chcesz odrzucić wszystkie zapisy zawierające wartości ranking, musisz zabronić zapisywania wszystkich dokumentów zawierających wartości ranking.

  {
    "rules": {
      // Write is allowed for all paths
      ".write": true,
      // Allows writes only if new data doesn't include a `ranking` child value
      ".validate": "!newData.hasChild('ranking')
    }
  }

Cloud Storage

Jeśli chcesz mieć pewność, że plik zawierający określone metadane nie zostanie utworzony, możesz uwzględnić te metadane w warunku allow. Jeśli na przykład chcesz zabronić tworzenia plików zawierających metadane ranking, musisz to zrobić w warunku create.

  service firebase.storage {
    match /b/{bucket}/o {
      match /files/{fileName} {
      // Disallow
        allow create: if !("ranking" in request.resource.metadata)
      }
    }
  }

Używanie istniejących danych w Firebase Security Rules

Cloud Firestore

Wiele aplikacji przechowuje informacje o kontroli dostępu jako pola w dokumentach w bazie danych. Cloud Firestore Security Rules może dynamicznie zezwalać na dostęp lub go odmawiać na podstawie danych dokumentu:

  service cloud.firestore {
    match /databases/{database}/documents {
      // Allow the user to read data if the document has the 'visibility'
      // field set to 'public'
      match /cities/{city} {
        allow read: if resource.data.visibility == 'public';
      }
    }
  }

Zmienna resource odnosi się do żądanego dokumentu, a resource.data to mapa wszystkich pól i wartości przechowywanych w dokumencie. Więcej informacji o zmiennej resource znajdziesz w dokumentacji.

Podczas zapisywania danych możesz chcieć porównać dane przychodzące z danymi już istniejącymi. Dzięki temu możesz na przykład sprawdzić, czy pole nie zostało zmienione, czy zwiększyło się tylko o 1 lub czy nowa wartość jest w przyszłości (co najmniej za tydzień). W takim przypadku, jeśli zestaw reguł zezwala na oczekujący zapis, zmienna request.resource zawiera przyszły stan dokumentu. W przypadku update operacji, które modyfikują tylko podzbiór pól dokumentu, zmienna request.resource będzie zawierać stan dokumentu oczekujący po operacji. Aby zapobiec niechcianym lub niespójnym aktualizacjom danych, możesz sprawdzić wartości pól w request.resource:

   service cloud.firestore {
     match /databases/{database}/documents {
      // Make sure all cities have a positive population and
      // the name is not changed
      match /cities/{city} {
        allow update: if request.resource.data.population > 0
                      && request.resource.data.name == resource.data.name;
      }
    }
  }

Realtime Database

W Realtime Database używaj .validate reguł, aby wymuszać struktury danych oraz weryfikować format i zawartość danych. Rules uruchamiaj .validate reguły po sprawdzeniu, czy .write reguła przyznaje dostęp.

Reguły .validate nie są kaskadowe. Jeśli w przypadku dowolnej ścieżki lub podścieżki w regule nie powiedzie się żadna reguła weryfikacji, cała operacja zapisu zostanie odrzucona. Dodatkowo weryfikacja definicji sprawdza tylko wartości inne niż null, a następnie ignoruje wszystkie żądania usuwania danych.

Weź pod uwagę te .validate reguły:

  {
    "rules": {
      // write is allowed for all paths
      ".write": true,
      "widget": {
        // a valid widget must have attributes "color" and "size"
        // allows deleting widgets (since .validate is not applied to delete rules)
        ".validate": "newData.hasChildren(['color', 'size'])",
        "size": {
          // the value of "size" must be a number between 0 and 99
          ".validate": "newData.isNumber() &&
                        newData.val() >= 0 &&
                        newData.val() <= 99"
        },
        "color": {
          // the value of "color" must exist as a key in our mythical
          // /valid_colors/ index
          ".validate": "root.child('valid_colors/' + newData.val()).exists()"
        }
      }
    }
  }

Żądania zapisu w bazie danych z powyższymi regułami dałyby te wyniki:

JavaScript
var ref = db.ref("/widget");

// PERMISSION_DENIED: does not have children color and size
ref.set('foo');

// PERMISSION DENIED: does not have child color
ref.set({size: 22});

// PERMISSION_DENIED: size is not a number
ref.set({ size: 'foo', color: 'red' });

// SUCCESS (assuming 'blue' appears in our colors list)
ref.set({ size: 21, color: 'blue'});

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child('size').set(99);
Objective-C
Uwaga: ta usługa Firebase nie jest dostępna w przypadku klipów z aplikacji.
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"];

// PERMISSION_DENIED: does not have children color and size
[ref setValue: @"foo"];

// PERMISSION DENIED: does not have child color
[ref setValue: @{ @"size": @"foo" }];

// PERMISSION_DENIED: size is not a number
[ref setValue: @{ @"size": @"foo", @"color": @"red" }];

// SUCCESS (assuming 'blue' appears in our colors list)
[ref setValue: @{ @"size": @21, @"color": @"blue" }];

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
[[ref child:@"size"] setValue: @99];
Swift
Uwaga: ta usługa Firebase nie jest dostępna w przypadku klipów z aplikacji.
var ref = FIRDatabase.database().reference().child("widget")

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo")

// PERMISSION DENIED: does not have child color
ref.setValue(["size": "foo"])

// PERMISSION_DENIED: size is not a number
ref.setValue(["size": "foo", "color": "red"])

// SUCCESS (assuming 'blue' appears in our colors list)
ref.setValue(["size": 21, "color": "blue"])

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
Java
FirebaseDatabase database = FirebaseDatabase.getInstance();
DatabaseReference ref = database.getReference("widget");

// PERMISSION_DENIED: does not have children color and size
ref.setValue("foo");

// PERMISSION DENIED: does not have child color
ref.child("size").setValue(22);

// PERMISSION_DENIED: size is not a number
Map<String,Object> map = new HashMap<String, Object>();
map.put("size","foo");
map.put("color","red");
ref.setValue(map);

// SUCCESS (assuming 'blue' appears in our colors list)
map = new HashMap<String, Object>();
map.put("size", 21);
map.put("color","blue");
ref.setValue(map);

// If the record already exists and has a color, this will
// succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
// will fail to validate
ref.child("size").setValue(99);
REST
# PERMISSION_DENIED: does not have children color and size
curl -X PUT -d 'foo' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION DENIED: does not have child color
curl -X PUT -d '{"size": 22}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# PERMISSION_DENIED: size is not a number
curl -X PUT -d '{"size": "foo", "color": "red"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# SUCCESS (assuming 'blue' appears in our colors list)
curl -X PUT -d '{"size": 21, "color": "blue"}' \
https://docs-examples.firebaseio.com/rest/securing-data/example.json

# If the record already exists and has a color, this will
# succeed, otherwise it will fail since newData.hasChildren(['color', 'size'])
# will fail to validate
curl -X PUT -d '99' \
https://docs-examples.firebaseio.com/rest/securing-data/example/size.json

Cloud Storage

Podczas oceny reguł możesz też oceniać metadane pliku przesyłanego, pobieranego, modyfikowanego lub usuwanego. Umożliwia to tworzenie złożonych i zaawansowanych reguł, które pozwalają na przykład zezwalać na przesyłanie tylko plików o określonych typach treści lub usuwać tylko pliki o określonym rozmiarze.

Obiekt resource zawiera pary klucz-wartość z metadanymi pliku, które są widoczne w obiekcie Cloud Storage. Te właściwości można sprawdzić w przypadku żądań read lub write, aby zapewnić integralność danych. Obiekt resource sprawdza metadane w istniejących plikach w zasobniku Cloud Storage.

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        match /{fileName} {
          // Allow reads if a custom 'visibility' field is set to 'public'
          allow read: if resource.metadata.visibility == 'public';
        }
      }
    }
  }

Możesz też używać obiektu request.resource w żądaniach write (np. w przypadku przesyłania, aktualizowania metadanych i usuwania). Obiekt request.resource pobiera metadane z pliku, który zostanie zapisany, jeśli write jest dozwolony.

Możesz użyć tych 2 wartości, aby zapobiec niechcianym lub niespójnym aktualizacjom albo wymusić ograniczenia aplikacji, takie jak typ lub rozmiar pliku.

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        // Allow write files to the path "images/*", subject to the constraints:
        // 1) File is less than 5MB
        // 2) Content type is an image
        // 3) Uploaded content type matches existing content type
        // 4) Filename (stored in imageId wildcard variable) is less than 32 characters
        match /{imageId} {
          allow read;
          allow write: if request.resource.size < 5 * 1024 * 1024
                       && request.resource.contentType.matches('image/.*')
                       && request.resource.contentType == resource.contentType
                       && imageId.size() < 32
        }
      }
    }
  }

Pełną listę właściwości obiektu resource znajdziesz w dokumentacji referencyjnej.