Protéger les données de vos clients avec les policies RLS Supabase
Vos clients vous confient leurs données : leur profil, leurs achats, leur progression. Tout cela vit dans les tables de votre base Supabase. Et tant que vous n'avez pas écrit de policies, vous ne savez pas vraiment qui peut lire quoi : une table restée ouverte, et un utilisateur connecté peut feuilleter les lignes des autres. Le pire, c'est que rien ne vous prévient : le site fonctionne exactement pareil, avec ou sans le verrou.
Cette masterclass vous donne la méthode des policies RLS : six pièces par table, montées toujours dans le même ordre, qui garantissent que chaque utilisateur ne voit, ne crée, ne modifie et ne supprime que ses propres données. Plus la requête d'audit qui vérifie qu'aucune table n'est restée ouverte.
Ce que cet exercice ne peut pas casser
Tout l'exercice se fait sur une feuille : vous ne touchez pas à votre base. Et au moment de passer au SQL, rien ne s'applique tant que vous ne l'avez pas collé vous-même : chaque bloc est précédé d'une phrase qui dit ce qu'il protège, vous savez toujours ce que vous êtes en train de fermer ou d'ouvrir.
Ce que vous saurez faire à la fin
- Décider, table par table, qui a le droit de lire, créer, modifier et supprimer chaque ligne.
- Monter les six pièces d'une table protégée, dans l'ordre, en commençant toujours par activer RLS.
- Vérifier avec une requête d'audit qu'aucune table de votre schéma public n'est restée ouverte.
- Reconnaître le piège de la clé service_role, qui contourne toutes vos policies.
- Niveau membre· le prompt prêt à coller qui rédige vos policies table par table à partir de votre matière, et vous donne la requête d'audit finale.
- Niveau Pro· je passe vos tables en revue avec vous et je pose les policies sur votre base, en direct.
Pour chaque table, le même montage, toujours dans cet ordre. Puis la requête d'audit vérifie qu'aucune table n'a été oubliée.
Les six pièces, et le tour de clé final
Une base bien protégée ne se ferme pas d'un grand geste : elle se ferme table par table, opération par opération. Pour chaque table, six pièces, toujours dans le même ordre : on pose le verrou, puis on rouvre la porte droit par droit, lecture, création, modification, suppression, et enfin les ouvertures volontaires, publiques ou administrateur. Cet ordre n'est pas décoratif : une policy écrite avant le verrou ne protège rien, et une table oubliée reste grande ouverte sans que rien ne vous prévienne.
1Activer RLS : le verrou avant toutdoute : « pourquoi tout disparaît d'un coup ? »
Première pièce, toujours : activer RLS sur la table, avant d'écrire la moindre policy. À la seconde où le verrou se pose, la table devient muette : sans policy, elle renvoie zéro ligne, même à son propriétaire. Ce silence n'est pas une panne, c'est la preuve que le verrou fonctionne. Les pièces suivantes rouvrent la porte, opération par opération, et uniquement pour les bonnes personnes.
2Lecture : chacun ne voit que ses lignesdoute : « comment la base sait à qui est la ligne ? »
La policy de lecture rend à chacun ses lignes : elle compare la colonne de propriété de la table, par défaut user_id, à l'identifiant de l'utilisateur connecté. La ligne lui appartient, il la voit. Sinon, elle n'existe pas pour lui. C'est la pièce qui fait que deux clients du même espace membre ne voient jamais l'historique l'un de l'autre.
3Création : rien ne s'écrit au nom d'un autredoute : « qui irait créer une ligne au nom d'un autre ? »
La lecture filtre ce qui sort, la création vérifie ce qui entre : la policy contrôle que toute nouvelle ligne porte bien l'identifiant de celui qui l'écrit. Sans cette vérification, rien n'empêche un utilisateur connecté d'insérer une ligne attribuée à quelqu'un d'autre. Chaque écriture doit être signée du bon nom, et c'est la base qui le garantit, pas votre formulaire.
4Modification : la pièce doubledoute : « la lecture ne suffit pas à protéger ? »
La modification cumule deux contrôles : on ne modifie que ses propres lignes, c'est le filtre sur la colonne de propriété, et on ne peut pas en profiter pour réattribuer la ligne à un autre, c'est la même vérification qu'à la création. Oublier l'un des deux laisse une porte entrouverte : la pièce ne tient que complète.
5Suppression : un droit qui se donne à partdoute : « encore une policy pour la même règle ? »
Oui, parce que chaque opération a sa propre policy : la suppression a la sienne, filtrée elle aussi sur la colonne de propriété. C'est tout l'intérêt de la méthode pièce par pièce : vous pouvez donner le droit de lire sans donner le droit de supprimer. Chaque droit accordé est une décision explicite, jamais un effet de bord.
6Public et admin : les ouvertures choisiesdoute : « et mes contenus visibles par tous ? »
Certaines tables contiennent des données publiques : pour celles-là, une policy de lecture ouverte, et seulement la lecture. Ajoutez si besoin une policy pour un rôle administrateur qui doit voir au-delà de ses propres lignes. Mais chaque ouverture est un risque qui se nomme : avant de l'écrire, dites en français simple ce qu'elle expose, et à qui.
7Le tour de clé final : l'auditdoute : « comment savoir si je n'ai rien oublié ? »
Une table oubliée est une table ouverte, et rien dans votre site ne vous le signalera. D'où le dernier geste, à rejouer après chaque nouvelle table : la requête qui liste les tables de votre schéma public où RLS n'est pas activé. Tant qu'elle renvoie une ligne, le travail n'est pas fini. Et un rappel qui vaut toutes les policies : la clé service_role contourne RLS. Elle reste côté serveur et ne s'expose jamais dans un navigateur.
À vous de jouer : votre registre d'accès
Prenez une feuille, une ligne par table. C'est la matière exacte que les six pièces attendent. Cochez à mesure.
Le résultat, en 30 secondes
À partir de votre seule matière, votre registre d'accès ou un export de votre schéma, le prompt déroule vos tables une par une : pour chacune, la règle d'accès résumée en français, puis le bloc SQL complet, chaque policy précédée d'un commentaire qui dit ce qu'elle protège.
Table commandes. Règle : chaque client lit, modifie et supprime uniquement ses propres commandes, et ne peut pas en créer au nom d'un autre. Puis le bloc SQL : activation de RLS, policy de lecture, de création, de modification, de suppression, chacune commentée. Et tout en bas : la requête d'audit qui liste les tables de votre schéma public sans RLS, à rejouer jusqu'à ce qu'elle ne renvoie plus rien.
Le prompt prêt à coller
# RÔLE Vous êtes un ingénieur Postgres et Supabase, rigoureux sur la sécurité des données. Votre exigence : une base où chaque utilisateur ne peut toucher que ses propres données, et zéro table oubliée. Vous ne vous appuyez QUE sur ce que je vous donne. Une table, une colonne ou une règle d'accès que je ne vous ai pas précisée, vous me la demandez. Vous n'inventez jamais un nom de table ni une colonne de propriété : si vous n'êtes pas sûr, vous le signalez et vous posez la question. # CONTEXTE Je protège un espace membre construit sur Supabase (Postgres). Je veux des policies RLS qui garantissent que chaque utilisateur ne voit, ne crée, ne modifie et ne supprime que ses propres données, plus la gestion des données publiques et d'un accès administrateur. Ma matière (si j'en ai) : [collez ici la liste de vos tables, leurs colonnes, et pour chaque table la colonne qui désigne le propriétaire de la ligne, par exemple user_id. Si vous avez un export du schéma, collez-le tel quel.]
Le prompt rédige vos policies table par table, les six pièces dans l'ordre, à partir de votre registre d'accès, chaque bloc SQL précédé d'une phrase qui dit ce qu'il protège. Vous partez de zéro ? Il passe en mode interview et vous questionne table par table avant d'écrire le moindre SQL. Laissez votre email, je vous l'envoie.
Vérifiez que c'est à vous
Vous activez RLS sur votre table commandes, puis vous passez à autre chose sans écrire de policy. Un client connecté ouvre la page de son historique d'achats. Que voit-il ?
D'abord avec vos mots, sans regarder les options :
Expliquez-le pour l'ancrer
Expliquez à un confrère, en une phrase, pourquoi on active RLS sur une table avant d'écrire la moindre policy, et ce qui se passe si on s'arrête là. Si vous savez le dire simplement, c'est à vous.
Ce que vous savez faire maintenant
- Les six pièces d'une table protégée : activation de RLS, lecture, création, modification, suppression, et les ouvertures publiques ou admin.
- Le réflexe du verrou d'abord, et la règle de la table muette : RLS sans policy, zéro ligne.
- La requête d'audit qui liste les tables de votre schéma public sans RLS, à rejouer après chaque nouvelle table.
- La règle service_role : cette clé contourne RLS et ne s'expose jamais côté navigateur.
Activez RLS d'abord, table par table, et ne laissez aucune table sans policy : une table oubliée est une table ouverte.
Faites-le avec moi
Je passe vos tables en revue avec vous, je pose les policies sur votre base et on rejoue la requête d'audit ensemble. Vous fermez votre base sans craindre la table oubliée.