Modèle de sécurité Edge Functions
Les règles qui maintiennent privés vos fonctions, leur code et leurs secrets, et les lieux dont vous restez responsable.
1. Clés et rôles
| Rôle | Clé | Peut faire |
|---|---|---|
anon | Clé publique, sécurisée dans un navigateur | Invoquer une fonction |
authenticated | Clé publique plus JWT d'un utilisateur connecté | Invoquer une fonction, avec l'identité de l'utilisateur |
service_role | Clé secrète, serveur uniquement | Tout : déployer, lire le code et les secrets, les tâches, le cron, les alertes |
admin | Une session console dans le Studio | Tout, du Studio |
Le rôle vient de la clé et du token, que la plateforme valide. Un client ne peut pas le choisir : un appel avec la clé publique et un en-tête x-aura-role: service_role parvient toujours à votre fonction en tant que anon.
Chaque route et son rôle sont répertoriés dans la référence de l'API HTTP .
2. Pourquoi seule l'invocation est publique
Une clé publique est publiée dans votre application Web ou mobile afin que tout le monde puisse la lire. Quoi que cela permette, tout le monde est autorisé. L'appel d'une fonction est la seule opération conçue pour cela : votre code décide de ce qu'un appelant peut faire.
La lecture de la définition d'une fonction est différente. Il contient le code source et les variables d'environnement, qui détiennent souvent des secrets. La liste des tâches et des alertes affiche vos données. La mise en file d'attente d'un travail exécute votre code sur votre quota. Aucun de ceux-ci ne peut être public, et la plateforme les refuse avec 403 pour toute clé autre que service_role.
La même fracture existe ailleurs. Supabase valide le JWT d'un utilisateur avant qu'une fonction Edge ne s'exécute par défaut (verify_jwt = true) et déploie des fonctions via sa CLI et sa plate-forme (docs). Firebase met en file d'attente les tâches d'un environnement de serveur de confiance via le SDK Admin, avec une autorisation IAM (docs). Cloudflare permet uniquement à un Worker d'envoyer vers une file d'attente, via une liaison (docs).
Les versions antérieures du service répondaient GET /v1/functions et GET /v1/functions/{name} à n'importe quelle clé. Si votre projet s'est exécuté sur un déploiement antérieur à ce correctif, traitez le code et les variables de vos fonctions comme exposés et alternez les secrets qu'ils contiennent. Voir Mise à niveau de vers 0.6.
3. L’identité ne peut pas être falsifiée
Votre fonction lit l'appelant depuis x-aura-role, x-aura-user-id et x-aura-project-id. La plateforme les définit après avoir validé la clé et le jeton.
- Un appelant ne peut pas les fournir. La plateforme supprime
authorization,apikey,x-request-idet tout en-têtex-aura-*envoyé dans leheadersd'une invocation, quel que soit leur cas. Lors d'un test réel, un appel avecx-aura-role: service_roleet un fauxauthorizationa atteint la fonction sous le nomrole: "anon"sansauthorization. - Les autres en-têtes personnalisés restent intacts. Traitez-les comme une entrée utilisateur.
- Les tâches et les tirs cron atteignent votre fonction sans en-têtes d'identité. Ils sont déclenchés par la plateforme et non par un utilisateur.
Autorisez donc sur x-aura-role et x-aura-user-id, jamais sur une valeur du corps :
4. Le bac à sable
Ce que la plateforme vous apporte :
- Chaque appel s'exécute dans son propre isolat V8, avec sa propre limite de mémoire et son propre délai d'expiration. Un crash ou une boucle infinie dans un appel n’affecte pas un autre.
- Les variables d'environnement de l'hôte sont invisibles :
Deno.env.get('PATH')a renvoyéundefinedlors d'une exécution réelle. Seules les variables de votre fonction et les variablesAURABASE_*de la plateforme sont présentes. - Le code d'un projet ne peut pas être lu par un autre : le service qui le sert nécessite un token interne.
- Les réponses qui peuvent exécuter des scripts sont servies avec une stratégie de sécurité du contenu en sandbox, et les en-têtes
Set-Cookieet CORS d'une fonction sont supprimés. Voir les réponses .
Ce qu'il fait, et non vous donne :
- Le réseau sortant est ouvert tant que vous ne le restreignez pas. Quand
permissions.allow_netliste au moins un hôte, le moteur refuse unfetchvers tout autre hôte (Requires net access to "host:443"). Une liste vide, la valeur par défaut, ne restreint rien. Listez chaque hôte dont la fonction a besoin, y compris l’URL de votre projet si elle appelle la plateforme. Même avec une liste, validez toute URL issue d’une saisie utilisateur. - Aucune protection de vos propres secrets dans les journaux. Tout ce que votre fonction écrit avec
console.logva dans les journaux d'exécution. - Aucune limite par utilisateur. La limite du taux d'appel est par adresse IP client. Ajoutez votre propre vérification si un utilisateur ne doit pas appeler une fonction plusieurs fois.
5. Liste de contrôle
- La clé
service_roleexiste uniquement sur vos serveurs et dans vos secrets CI. - Le bundle du navigateur contient uniquement la clé publique. Le SDK refuse par défaut une clé
service_roledans un navigateur. - Chaque fonction vérifie
x-aura-roleavant de faire quoi que ce soit de sensible. - Les secrets sont des variables de la fonction, jamais dans
index.ts. - Les fonctions qui appellent des URL externes valident la destination.
- Vous faites pivoter une clé en en créant une nouvelle dans le Studio, en la déployant en tant que secret, puis en révoquant l'ancienne.