Comprendre les règles de sécurité Firebase Realtime Database

Les règles de sécurité Firebase Realtime Database déterminent qui a accès en lecture et en écriture à votre base de données, la structure de vos données et les index existants. Ces règles sont stockées sur les serveurs Firebase et appliquées automatiquement en permanence. Chaque requête de lecture et d'écriture ne sera traitée que si vos règles l'autorisent. Par défaut, vos règles n'autorisent personne à accéder à votre base de données. Cela permet de protéger votre base de données contre les utilisations abusives jusqu'à ce que vous ayez le temps de personnaliser vos règles ou de configurer l'authentification.

Les règles de sécurité Realtime Database ont une syntaxe semblable à JavaScript et se déclinent en quatre types :

Types de règles
.read Indique si et quand les utilisateurs sont autorisés à lire les données.
.write Indique si et quand les données peuvent être écrites.
.validate Définit l'apparence d'une valeur correctement formatée, qu'elle comporte des attributs enfants ou non, et le type de données.
.indexOn Spécifie un enfant à indexer pour prendre en charge le tri et les requêtes.

Realtime Database Présentation de la sécurité

Firebase Realtime Database fournit un ensemble complet d'outils pour gérer la sécurité de votre application. Ces outils permettent d'authentifier facilement vos utilisateurs, d'appliquer les autorisations des utilisateurs et de valider les entrées.

Les applications optimisées par Firebase exécutent plus de code côté client que celles qui utilisent de nombreuses autres piles technologiques. Par conséquent, notre approche de la sécurité peut être un peu différente de celle à laquelle vous êtes habitué.

Authentification

Une première étape courante pour sécuriser votre application consiste à identifier vos utilisateurs. Ce processus est appelé authentification. Vous pouvez utiliser Firebase Authentication pour permettre aux utilisateurs de se connecter à votre application. Firebase Authentication inclut une prise en charge prête à l'emploi des méthodes d'authentification courantes telles que Google et Facebook, ainsi que la connexion par adresse e-mail et mot de passe, la connexion anonyme, etc.

L'identité de l'utilisateur est un concept de sécurité important. Différents utilisateurs ont des données différentes et, parfois, des capacités différentes. Par exemple, dans une application de chat, chaque message est associé à l'utilisateur qui l'a créé. Les utilisateurs peuvent également supprimer leurs propres messages, mais pas ceux publiés par d'autres utilisateurs.

Autorisation

L'identification de vos utilisateurs n'est qu'une partie de la sécurité. Une fois que vous savez qui ils sont, vous devez trouver un moyen de contrôler leur accès aux données de votre base de données. Les règles de sécurité Realtime Database vous permettent de contrôler l'accès de chaque utilisateur. Par exemple, voici un ensemble de règles de sécurité qui autorisent tout le monde à lire le chemin /foo/, mais personne à y écrire :

{
  "rules": {
    "foo": {
      ".read": true,
      ".write": false
    }
  }
}

Les règles .read et .write sont en cascade. Cet ensemble de règles accorde donc un accès en lecture à toutes les données du chemin /foo/, ainsi qu'à tous les chemins plus profonds, tels que /foo/bar/baz. Notez que les règles .read et .write moins profondes dans la base de données remplacent les règles plus profondes. Par conséquent, l'accès en lecture à /foo/bar/baz serait toujours accordé dans cet exemple, même si une règle au chemin d'accès /foo/bar/baz était évaluée à "false".

Les règles de sécurité Realtime Database incluent des variables intégrées et des fonctions qui vous permettent de faire référence à d'autres chemins d'accès, à des codes temporels côté serveur, à des informations d'authentification, etc. Voici un exemple de règle qui accorde un accès en écriture aux utilisateurs authentifiés pour /users/<uid>/, où <uid> correspond à l'ID de l'utilisateur obtenu via Firebase Authentication.

{
  "rules": {
    "users": {
      "$uid": {
        ".write": "$uid === auth.uid"
      }
    }
  }
}

Validation des données

Le Firebase Realtime Database est sans schéma. Cela facilite les modifications au fur et à mesure du développement. Toutefois, une fois votre application prête à être distribuée, il est important que les données restent cohérentes. Le langage des règles inclut une règle .validate qui vous permet d'appliquer une logique de validation à l'aide des mêmes expressions que celles utilisées pour les règles .read et .write. La seule différence est que les règles de validation ne sont pas appliquées en cascade. Par conséquent, toutes les règles de validation pertinentes doivent être évaluées comme étant vraies pour que l'écriture soit autorisée.

Ces règles imposent que les données écrites dans /foo/ doivent être une chaîne de caractères de moins de 100 caractères :

{
  "rules": {
    "foo": {
      ".validate": "newData.isString() && newData.val().length < 100"
    }
  }
}

Les règles de validation ont accès à toutes les fonctions et variables intégrées des règles .read et .write. Vous pouvez les utiliser pour créer des règles de validation qui tiennent compte des données ailleurs dans votre base de données, de l'identité de votre utilisateur, de l'heure du serveur et bien plus encore.

Définir des index de base de données

Firebase Realtime Database permet de trier et d'interroger les données. Pour les petites quantités de données, la base de données est compatible avec les requêtes ad hoc. Les index ne sont donc généralement pas nécessaires pendant le développement. Toutefois, avant de lancer votre application, il est important de spécifier des index pour toutes les requêtes que vous avez afin de vous assurer qu'elles continuent de fonctionner à mesure que votre application se développe.

Les index sont spécifiés à l'aide de la règle .indexOn. Voici un exemple de déclaration d'index qui indexerait les champs "height" (hauteur) et "length" (longueur) pour une liste de dinosaures :

{
  "rules": {
    "dinosaurs": {
      ".indexOn": ["height", "length"]
    }
  }
}

Étapes suivantes