Ce guide s'appuie sur l' apprentissage de la syntaxe de base du guide du langage des règles de sécurité Firebase pour montrer comment ajouter des conditions à vos règles de sécurité Firebase pour Cloud Storage.
Le bloc de construction principal des règles de sécurité Cloud Storage 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, l'utilisation de littéraux true
et false
comme conditions fonctionne parfaitement bien. 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 authentification puissante basée sur l'utilisateur à 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 auprès de Cloud Storage, la variable request.auth
est renseignée avec l' uid
de l'utilisateur ( request.auth.uid
) ainsi que les revendications du Firebase Authentication JWT ( request.auth.token
).
De plus, lors de l'utilisation d'une 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 façons 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 à un pathuid
- Groupe privé : vérifiez que les revendications du jeton personnalisé correspondent à une revendication choisie ou lisez les métadonnées du fichier pour voir si un champ de métadonnées existe
Public
Toute règle qui ne tient pas compte du contexte request.auth
peut être considérée comme une règle public
, car elle ne tient pas compte du contexte d'authentification de l'utilisateur. Ces règles peuvent être utiles pour afficher des données publiques telles que des éléments de jeu, des fichiers audio ou d'autres contenus statiques.
// 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. La variable request.auth
étant null
pour tous les utilisateurs non authentifiés, il suffit de vérifier que la variable request.auth
existe pour demander 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 pour 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 un élément d'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é 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 de l'équipe de collaborer sur un document partagé. Il existe plusieurs approches pour le faire :
- Créer un jeton personnalisé d'authentification Firebase qui contient des informations supplémentaires sur un membre du groupe (comme un ID 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; }
Demande d'évaluation
Les importations, 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 demande est effectuée, l'heure à laquelle la demande est reçue et la nouvelle valeur resource
si la requête est une écriture.
L'objet request
contient également l'ID unique de l'utilisateur et la charge utile Firebase Authentication 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 dans l'objet request
est disponible ci-dessous :
Propriété | Taper | Description |
---|---|---|
auth | carte<chaîne, chaîne> | Lorsqu'un utilisateur est connecté, fournit uid , l'ID unique de l'utilisateur et token , une carte des revendications Firebase Authentication JWT. Sinon, ce sera null . |
params | carte<chaîne, chaîne> | Carte contenant les paramètres de requête de la requête. |
path | chemin | Un path représentant le chemin sur lequel la requête est exécutée. |
resource | carte<chaîne, chaîne> | 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 pouvez également souhaiter é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 autorisent uniquement le téléchargement de fichiers avec certains types de contenu ou la suppression de seuls fichiers supérieurs à 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 présentées 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 de fichier pour le fichier qui existe actuellement sur le 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 des fichiers.
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 compartiment dans lequel cet objet réside. |
generation | entier | La génération d'objet Google Cloud Storage de cet objet. |
metageneration | entier | La métagénération d'objet Google Cloud Storage de cet objet. |
size | entier | 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 | Etag associé à cet objet. |
contentDisposition | chaîne | Disposition du contenu associée à cet objet. |
contentEncoding | chaîne | Le codage de contenu associé à cet objet. |
contentLanguage | chaîne | La langue du contenu associée à cet objet. |
contentType | chaîne | Type de contenu associé à cet objet. |
metadata | carte<chaîne, chaîne> | 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éliorer 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 document entièrement spécifiés. Lorsque vous utilisez des variables pour construire des chemins pour firestore.get()
et firestore.exists()
, vous devez explicitement échapper les variables à l'aide de la syntaxe $(variable)
.
Dans l'exemple ci-dessous, nous voyons une règle qui limite l'accès en lecture aux fichiers aux utilisateurs qui sont 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 la CLI Firebase à activer les autorisations pour 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, y compris la validation du nom et du chemin du fichier ainsi que les 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
Au fur et à mesure que vos règles de sécurité Firebase deviennent plus complexes, vous souhaiterez peut-être encapsuler des ensembles de conditions dans des fonctions que vous pourrez 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 à un domaine qui présente des 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 ou 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 être récursives. 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 pouvez combiner les deux types de conditions utilisées 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 maintenables à 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 principaux cas d'utilisation et découvrez le flux de travail pour développer, tester et déployer des règles :
- Rédigez des règles qui répondent à des scénarios courants .
- Renforcez vos connaissances en examinant les situations où 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 test dédiée aux règles de sécurité .
- Passez en revue les méthodes disponibles pour déployer des règles .