Validação de dados

É possível usar as regras de segurança do Firebase para gravar, de modo condicional, novos dados com base nas informações presentes no banco de dados ou no intervalo de armazenamento. Além disso, é possível gravar regras que apliquem validações de dados por meio da restrição de gravações com base nos novos dados que estão sendo gravados. Continue lendo para saber mais sobre as regras que usam dados atuais para criar condições de segurança.

Selecione um produto em cada seção para saber mais sobre as regras de validação de dados.

Restrições a novos dados

Cloud Firestore

Se você quiser garantir que um documento que contenha um campo específico não seja criado, inclua o campo na condição allow. Por exemplo, se você quiser negar a criação de qualquer documento que contenha o campo ranking, não será permitido na condição create.

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

Realtime Database

Se você quiser garantir que as informações que contêm determinados valores não sejam adicionadas ao seu banco de dados, inclua esses valores nas regras e bloqueie a gravação delas. Por exemplo, se você quiser negar qualquer gravação que contenha os valores de ranking, bloqueie as gravações de qualquer documento com os valores de 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

Se você quiser garantir que um arquivo que contém metadados específicos não seja criado, inclua esses metadados na condição allow. Por exemplo, se quiser negar a criação de qualquer arquivo que contenha metadados de ranking, bloqueie-os na condição create.

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

Usar dados atuais nas regras de segurança do Firebase

Cloud Firestore

Muitos aplicativos armazenam informações de controle de acesso como campos em documentos no banco de dados. As regras de segurança do Cloud Firestore podem permitir ou negar acesso dinamicamente com base nos dados do documento:

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

A variável resource refere-se ao documento solicitado, e resource.data é um mapa de todos os campos e valores armazenados no documento. Para mais informações sobre a variável resource, consulte a documentação de referência.

Ao gravar dados, pode ser necessário comparar as informações novas com as existentes. Dessa forma, é possível garantir, por exemplo, que um campo não seja alterado, que ele tenha o valor incrementado em apenas um ou que o novo valor esteja pelo menos uma semana no futuro. Nesse caso, se o conjunto de regras permitir a gravação pendente, a variável request.resource conterá o estado futuro do documento. Para operações update que apenas modificam um subconjunto dos campos do documento, a variável request.resource conterá o estado do documento pendente após a operação. É possível verificar os valores dos campos em request.resource para evitar atualizações de dados indesejados ou inconsistentes:

   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

No Realtime Database, use regras .validate para aplicar estruturas de dados e validar o formato e o conteúdo deles. As regras executam regras .validate depois de verificar se uma regra .write concede acesso.

As regras .validate não são aplicadas em cascata. Se qualquer regra de validação falhar em qualquer caminho ou subcaminho, a operação de gravação como um todo será recusada. Além disso, as definições de validação verificam se há apenas valores não nulos e, em seguida, ignora qualquer solicitação que exclua dados.

Suponha as seguintes regras .validate:

  {
    "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()"
        }
      }
    }
  }

As solicitações de gravação para um banco de dados que use as regras acima teriam os seguintes resultados:

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
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
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

Durante a avaliação de regras, é possível também examinar os metadados do arquivo que está sendo modificado, excluído ou transferido por upload ou download. Crie regras complexas e eficazes, como permitir o upload somente de arquivos com um conteúdo específico ou apenas a exclusão de arquivos maiores com um tamanho determinado.

O objeto resource contém pares de chave-valor com metadados de arquivo exibidos em um objeto do Cloud Storage. Essas propriedades podem ser inspecionadas em solicitações read ou write para garantir a integridade dos dados. O objeto resource verifica os metadados nos arquivos existentes no intervalo do Storage.

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

Também é possível usar o objeto request.resource em solicitações write (como uploads, atualizações de metadados e exclusões). O objeto request.resource recebe metadados do arquivo que será gravado se o write for permitido.

Use esses dois valores para impedir atualizações não solicitadas ou inconsistentes ou para aplicar restrições de aplicativo, como tipo ou tamanho de arquivo.

  service firebase.storage {
    match /b/{bucket}/o {
      match /images {
        // Cascade read to any image type at any path
        match /{allImages=**} {
          allow read;
        }

        // 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) File name (stored in imageId wildcard variable) is less than 32 characters
        match /{imageId} {
          allow write: if request.resource.size < 5 * 1024 * 1024
                       && request.resource.contentType.matches('image/.*')
                       && request.resource.contentType == resource.contentType
                       && imageId.size() < 32
        }
      }
    }
  }

Uma lista completa de propriedades no objeto resource está disponível na documentação de referência.