Ce guide s'appuie sur l' apprentissage de la syntaxe de base du guide linguistique des règles de sécurité Firebase pour montrer comment ajouter des conditions à vos règles de sécurité Firebase pour le stockage dans le cloud.
Le principal élément constitutif des règles de sécurité du stockage cloud est la condition . Une condition est une expression booléenne qui détermine si une opération particulière doit être autorisée ou refusée. Pour les règles de base, utiliser des littéraux true
et false
comme conditions fonctionne parfaitement. Mais le langage Firebase Security Rules for Cloud Storage vous permet d'écrire des conditions plus complexes qui peuvent :
- Vérifier l'authentification de l'utilisateur
- Valider les données entrantes
Authentification
Les règles de sécurité Firebase pour Cloud Storage s'intègrent à Firebase Authentication pour fournir une puissante authentification basée sur l'utilisateur sur Cloud Storage. Cela permet un contrôle d'accès granulaire basé sur les revendications d'un jeton d'authentification Firebase.
Lorsqu'un utilisateur authentifié effectue une requête sur Cloud Storage, la variable request.auth
est renseignée avec l' uid
de l'utilisateur ( request.auth.uid
) ainsi que les revendications du JWT d'authentification Firebase ( request.auth.token
).
De plus, lors de l'utilisation de l'authentification personnalisée, des revendications supplémentaires apparaissent dans le champ request.auth.token
.
Lorsqu'un utilisateur non authentifié effectue une requête, la variable request.auth
est null
.
À l'aide de ces données, il existe plusieurs manières courantes d'utiliser l'authentification pour sécuriser les fichiers :
- Public : ignorer
request.auth
- Privé authentifié : vérifiez que
request.auth
n'est pasnull
- Utilisateur privé : vérifiez que
request.auth.uid
est égal à unuid
de chemin - Groupe privé : vérifiez les revendications du jeton personnalisé pour qu'elles correspondent à une revendication choisie, ou lisez les métadonnées du fichier pour voir si un champ de métadonnées existe
Publique
Toute règle qui ne prend pas en compte le contexte request.auth
peut être considérée comme une règle public
, car elle ne prend pas en compte le contexte d'authentification de l'utilisateur. Ces règles peuvent être utiles pour faire apparaître des données publiques telles que des ressources de jeu, des fichiers audio ou tout autre contenu statique.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
Privé authentifié
Dans certains cas, vous souhaiterez peut-être que les données soient visibles par tous les utilisateurs authentifiés de votre application, mais pas par les utilisateurs non authentifiés. Puisque la variable request.auth
est null
pour tous les utilisateurs non authentifiés, il suffit de vérifier que la variable request.auth
existe afin d'exiger une authentification :
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
Utilisateur privé
Le cas d'utilisation de loin le plus courant de request.auth
sera de fournir aux utilisateurs individuels des autorisations granulaires sur leurs fichiers : du téléchargement de photos de profil à la lecture de documents privés.
Étant donné que les fichiers dans Cloud Storage ont un « chemin » complet vers le fichier, tout ce qu'il faut pour qu'un fichier soit contrôlé par un utilisateur est une information unique d'identification de l'utilisateur dans le préfixe du nom de fichier (comme l' uid
de l'utilisateur) qui peut être vérifiée. lorsque la règle est évaluée :
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
Groupe privé
Un autre cas d'utilisation tout aussi courant consistera à autoriser des autorisations de groupe sur un objet, par exemple en permettant à plusieurs membres d'une équipe de collaborer sur un document partagé. Il existe plusieurs approches pour y parvenir :
- Créez un jeton personnalisé d'authentification Firebase qui contient des informations supplémentaires sur un membre du groupe (telles qu'un identifiant de groupe)
- Inclure des informations de groupe (telles qu'un ID de groupe ou une liste d'
uid
autorisés) dans les métadonnées du fichier
Une fois ces données stockées dans les métadonnées du jeton ou du fichier, elles peuvent être référencées à partir d'une règle :
// Allow reads if the group ID in your token matches the file metadata's `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; }
Demander une évaluation
Les chargements, les téléchargements, les modifications de métadonnées et les suppressions sont évalués à l'aide de la request
envoyée à Cloud Storage. En plus de l'ID unique de l'utilisateur et de la charge utile d'authentification Firebase dans l'objet request.auth
comme décrit ci-dessus, la variable request
contient le chemin du fichier où la requête est exécutée, l'heure à laquelle la requête est reçue et la nouvelle valeur resource
si la demande est une écriture.
L'objet request
contient également l'ID unique de l'utilisateur et la charge utile d'authentification Firebase dans l'objet request.auth
, qui sera expliqué plus en détail dans la section Sécurité basée sur l'utilisateur de la documentation.
Une liste complète des propriétés de l'objet request
est disponible ci-dessous :
Propriété | Taper | Description |
---|---|---|
auth | carte<string, string> | Lorsqu'un utilisateur est connecté, fournit uid , l'ID unique de l'utilisateur et token , une carte des revendications JWT d'authentification Firebase. Sinon, ce sera null . |
params | carte<string, string> | Carte contenant les paramètres de requête de la requête. |
path | chemin | Un path représentant le chemin sur lequel la demande est exécutée. |
resource | carte<string, string> | La nouvelle valeur de ressource, présente uniquement sur les demandes write . |
time | horodatage | Un horodatage représentant l'heure du serveur à laquelle la demande est évaluée. |
Évaluation des ressources
Lors de l'évaluation des règles, vous souhaiterez peut-être également évaluer les métadonnées du fichier en cours de chargement, de téléchargement, de modification ou de suppression. Cela vous permet de créer des règles complexes et puissantes qui permettent par exemple d'autoriser uniquement le téléchargement de fichiers avec certains types de contenu ou la suppression de uniquement des fichiers d'une taille supérieure à une certaine taille.
Les règles de sécurité Firebase pour Cloud Storage fournissent des métadonnées de fichier dans l'objet resource
, qui contient des paires clé/valeur des métadonnées apparues dans un objet Cloud Storage. Ces propriétés peuvent être inspectées lors de demandes read
ou write
pour garantir l'intégrité des données.
Sur les demandes write
(telles que les téléchargements, les mises à jour de métadonnées et les suppressions), en plus de l'objet resource
, qui contient les métadonnées du fichier qui existe actuellement au niveau du chemin de la demande, vous avez également la possibilité d'utiliser l'objet request.resource
, qui contient un sous-ensemble des métadonnées du fichier à écrire si l'écriture est autorisée. Vous pouvez utiliser ces deux valeurs pour garantir l'intégrité des données ou appliquer des contraintes d'application telles que le type ou la taille du fichier.
Une liste complète des propriétés de l'objet resource
est disponible ci-dessous :
Propriété | Taper | Description |
---|---|---|
name | chaîne | Le nom complet de l'objet |
bucket | chaîne | Le nom du bucket dans lequel réside cet objet. |
generation | int | Génération d'objet Google Cloud Storage de cet objet. |
metageneration | int | Métagénération d'objet Google Cloud Storage de cet objet. |
size | int | La taille de l'objet en octets. |
timeCreated | horodatage | Un horodatage représentant l’heure à laquelle un objet a été créé. |
updated | horodatage | Un horodatage représentant l’heure à laquelle un objet a été mis à jour pour la dernière fois. |
md5Hash | chaîne | Un hachage MD5 de l'objet. |
crc32c | chaîne | Un hachage crc32c de l'objet. |
etag | chaîne | L'étiquette associée à cet objet. |
contentDisposition | chaîne | Disposition du contenu associée à cet objet. |
contentEncoding | chaîne | L'encodage du contenu associé à cet objet. |
contentLanguage | chaîne | La langue du contenu associée à cet objet. |
contentType | chaîne | Le type de contenu associé à cet objet. |
metadata | carte<string, string> | Paires clé/valeur de métadonnées personnalisées supplémentaires spécifiées par le développeur. |
request.resource
contient tous ces éléments à l'exception de generation
, metageneration
, etag
, timeCreated
et updated
.
Améliorez avec Cloud Firestore
Vous pouvez accéder aux documents dans Cloud Firestore pour évaluer d'autres critères d'autorisation.
À l'aide des fonctions firestore.get()
et firestore.exists()
, vos règles de sécurité peuvent évaluer les requêtes entrantes par rapport aux documents dans Cloud Firestore. Les fonctions firestore.get()
et firestore.exists()
attendent toutes deux des chemins de documents entièrement spécifiés. Lorsque vous utilisez des variables pour construire des chemins pour firestore.get()
et firestore.exists()
, vous devez échapper explicitement aux variables en utilisant la syntaxe $(variable)
.
Dans l'exemple ci-dessous, nous voyons une règle qui restreint l'accès en lecture aux fichiers aux utilisateurs membres de clubs particuliers.
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships } } }Dans l'exemple suivant, seuls les amis d'un utilisateur peuvent voir ses photos.
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id)) } } }
Une fois que vous avez créé et enregistré vos premières règles de sécurité Cloud Storage qui utilisent ces fonctions Cloud Firestore, vous serez invité dans la console Firebase ou Firebase CLI pour activer les autorisations permettant de connecter les deux produits.
Vous pouvez désactiver la fonctionnalité en supprimant un rôle IAM, comme décrit dans Gérer et déployer les règles de sécurité Firebase .
Valider les données
Les règles de sécurité Firebase pour Cloud Storage peuvent également être utilisées pour la validation des données, notamment la validation du nom et du chemin du fichier ainsi que des propriétés des métadonnées du fichier telles que contentType
et size
.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
Fonctions personnalisées
À mesure que vos règles de sécurité Firebase deviennent plus complexes, vous souhaiterez peut-être regrouper des ensembles de conditions dans des fonctions que vous pouvez réutiliser dans votre ensemble de règles. Les règles de sécurité prennent en charge les fonctions personnalisées. La syntaxe des fonctions personnalisées ressemble un peu à JavaScript, mais les fonctions des règles de sécurité Firebase sont écrites dans un langage spécifique au domaine qui présente certaines limitations importantes :
- Les fonctions ne peuvent contenir qu'une seule instruction
return
. Ils ne peuvent contenir aucune logique supplémentaire. Par exemple, ils ne peuvent pas exécuter de boucles ni appeler des services externes. - Les fonctions peuvent accéder automatiquement aux fonctions et aux variables à partir de la portée dans laquelle elles sont définies. Par exemple, une fonction définie dans la portée
service firebase.storage
a accès à la variableresource
et, pour Cloud Firestore uniquement, aux fonctions intégrées telles queget()
etexists()
. - Les fonctions peuvent appeler d'autres fonctions mais ne peuvent pas récidiver. La profondeur totale de la pile d’appels est limitée à 10.
- Dans la version
rules2
, les fonctions peuvent définir des variables à l'aide du mot-clélet
. Les fonctions peuvent avoir n'importe quel nombre de liaisons let, mais doivent se terminer par une instruction return.
Une fonction est définie avec le mot-clé function
et prend zéro ou plusieurs arguments. Par exemple, vous souhaiterez peut-être combiner les deux types de conditions utilisés dans les exemples ci-dessus en une seule fonction :
service firebase.storage {
match /b/{bucket}/o {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
L'utilisation de fonctions dans vos règles de sécurité Firebase les rend plus faciles à maintenir à mesure que la complexité de vos règles augmente.
Prochaines étapes
Après cette discussion sur les conditions, vous avez une compréhension plus sophistiquée des règles et êtes prêt à :
Apprenez à gérer les cas d'utilisation principaux et découvrez le flux de travail pour développer, tester et déployer des règles :
- Écrivez des règles qui répondent à des scénarios courants .
- Développez vos connaissances en examinant les situations dans lesquelles vous devez repérer et éviter les règles non sécurisées .
- Testez les règles à l'aide de l'émulateur Cloud Storage et de la bibliothèque de tests dédiée aux règles de sécurité .
- Passez en revue les méthodes disponibles pour déployer des règles .