Supabase : vérifier vos règles d'accès en dix minutes
Votre application lit ses données directement depuis le navigateur. Une seule chose empêche un inconnu de lire celles de vos clients : les règles d'accès de la base. Voici comment vérifier qu'elles font leur travail.
Pourquoi c'est la première chose à vérifier
Dans une application Supabase, le navigateur parle directement à la base de données. Pour cela, il utilise une clé publique, dite « anon » (ou « publishable » sur les projets récents), visible dans le code de chaque page : c'est normal, Supabase est conçu ainsi. Cette clé n'est donc pas un secret, et n'importe qui peut l'utiliser.
Ce qui protège vos données, ce ne sont pas les écrans de votre application, mais les règles d'accès de la base, que Supabase appelle Row Level Security (RLS). Elles décident, ligne par ligne, qui peut lire ou modifier quoi. Si elles sont absentes ou trop larges, les données de vos clients sont lisibles par quiconque connaît l'adresse de votre projet, sans compte, sans mot de passe.
C'est le défaut le plus fréquent dans les applications générées par une IA, et le plus grave, parce qu'il expose des données personnelles aujourd'hui, sans que rien ne casse à l'écran.
Étape 1 : chaque table a-t-elle ses règles activées ?
Dans le tableau de bord Supabase, ouvrez le menu Advisors, puis Security Advisor. Il signale en rouge les tables dont les règles d'accès sont désactivées (« RLS disabled »). Une table sans règles, dans le schéma public, est ouverte à tous.
Pour une vue complète, ouvrez le SQL Editor et lancez :
select tablename, rowsecurity
from pg_tables
where schemaname = 'public'
order by tablename;
Chaque ligne doit afficher true dans la colonne rowsecurity. Une seule ligne à false sur une table qui contient des clients, des commandes ou des paiements, et vous avez trouvé votre premier problème.
Étape 2 : que disent les règles ?
Activer les règles ne suffit pas : encore faut-il qu'elles restreignent quelque chose. Toujours dans le SQL Editor :
select tablename, policyname, cmd, roles, qual, with_check
from pg_policies
where schemaname = 'public'
order by tablename, policyname;
Lisez la colonne qual, c'est la condition (pour les règles de création, INSERT, la condition est dans la colonne with_check : un with_check à true laisse n'importe qui créer des lignes). Trois signaux d'alarme :
true: la règle laisse passer tout le monde. Acceptable pour un catalogue public, jamais pour des profils, des réservations ou des paiements.- un nom comme « allow all », « public access », « enable read for all » : souvent une règle posée au premier jour « pour démarrer », et jamais retirée.
rolescontenantpublicouanon, avec une condition qui ne vérifie pas l'utilisateur (true, ou seulement une colonne commestatus = 'actif') sur une table personnelle : la règle s'applique aussi aux visiteurs sans compte. (publicseul est la valeur par défaut : une règleauth.uid() = user_idappliquée àpublicreste sûre.)
Une bonne règle sur une table personnelle compare l'utilisateur connecté au propriétaire de la ligne, par exemple auth.uid() = user_id.
Le piège : les règles s'additionnent
C'est ici que la plupart des applications se trompent. Dans Postgres, les règles d'une même table (celles de type « permissive », le cas par défaut) s'additionnent : il suffit qu'une seule laisse passer pour que l'accès soit accordé.
Conséquence : vous pouvez avoir ajouté, plus tard, des règles parfaitement écrites (« chacun ne voit que ses réservations ») : si l'ancienne règle « allow all » est toujours là, elle l'emporte. Les règles récentes donnent alors une fausse impression de sécurité à qui les relit.
C'est exactement ce que montre notre diagnostic de Studio Kerelune, l'application que nous avons construite pour la disséquer en public : la règle « allow all » du premier jour n'avait jamais été retirée, et un visiteur sans compte lisait l'e-mail et le téléphone de tous les clients.
Donc : pour chaque table, lisez toutes ses règles ensemble, pas seulement la plus récente.
Étape 3 : le test qui tranche
Les étapes 1 et 2 se lisent. Celle-ci se vérifie, sur votre propre projet : on demande à la base ce qu'elle répond à un visiteur sans compte.
Récupérez l'adresse de votre projet et sa clé publique dans les paramètres du projet (rubrique API ou API Keys), puis, dans un terminal :
curl "https://VOTRE-PROJET.supabase.co/rest/v1/profiles?select=*&limit=3" \
-H "apikey: VOTRE_CLE_ANON"
Avec une ancienne clé « anon », ajoutez aussi -H "Authorization: Bearer VOTRE_CLE_ANON". Remplacez profiles par le nom de chacune de vos tables qui contiennent des données personnelles.
- La réponse est
[](une liste vide) ou une erreur de droits : la table est protégée pour un visiteur sans compte (vérifiez d'abord dans le Table Editor que la table contient bien des lignes). - La réponse contient des lignes : ces données sont lisibles par n'importe qui sur Internet, aujourd'hui.
Faites le même test une fois connecté avec un compte client ordinaire. Le plus simple : connectez-vous dans l'application, ouvrez l'onglet Réseau des outils de développement, et regardez la réponse des requêtes /rest/v1/ : elle ne doit contenir que les lignes de ce client.
Étape 4 : un client peut-il modifier ce qu'il ne devrait pas ?
Une règle de modification trop large permet à un client de changer des colonnes sensibles de sa propre ligne : son rôle (« admin »), son solde, son statut de paiement. Dans le résultat de l'étape 2, regardez les règles dont cmd vaut UPDATE ou ALL sur une table qui contient un rôle, un montant ou un statut. Si la condition se contente de auth.uid() = id, le client peut modifier toutes les colonnes de sa ligne, y compris son rôle.
Ce que ces dix minutes ne couvrent pas
Ces vérifications couvrent l'essentiel, pas tout :
- les fichiers déposés (avatars, documents), protégés par des règles à part, dans Storage ;
- les fonctions de la base marquées
security definer, qui ignorent les règles d'accès ; - les vues de la base, qui par défaut ne respectent pas les règles d'accès des tables qu'elles lisent (le Security Advisor les signale) ;
- les fonctions serveur (Edge Functions) ouvertes sans vérification de l'appelant ;
- et la clé d'administration (
service_role), qui contourne toutes les règles : si elle se trouve dans le code de votre application, rien de ce qui précède ne vous protège. Voir notre guide La clé d'administration est-elle dans votre code ?.
Si vous avez trouvé un problème
Corriger tient souvent en quelques lignes : supprimer la règle trop large, écrire une règle par usage (lecture, création, modification) qui compare l'utilisateur au propriétaire de la ligne, interdire la modification des colonnes sensibles. Puis refaire le test de l'étape 3, qui doit tout refuser au visiteur sans compte.
Si vous préférez ne pas y toucher seul, notre intervention ciblée corrige ce problème précis à 690 € HT, prix ferme. Si vous voulez savoir ce qu'il y a d'autre, c'est notre diagnostic : soixante questions sur sept axes, chaque constat prouvé, et un plan chiffré.
Vous préférez qu'on regarde avec vous ?
Le diagnostic couvre ce guide et toute la grille, soixante questions sur sept axes, pour 2 900 € HT : premiers constats sous 48 heures, rapport sous cinq jours ouvrés.