Une seule table sans RLS, et toute votre base devient publique
Sur Supabase, chaque table exposée via l'API est lisible par n'importe qui tant que la Row Level Security n'est pas activée. Résultat concret : des applications lancées en quelques heures avec l'IA ont laissé fuiter emails, messages privés et données de paiement de tous leurs utilisateurs. Le coupable est presque toujours le même : une RLS mal comprise, ou tout simplement oubliée.
Dans cet article, vous allez découvrir :
- •Ce qu'est vraiment la Row Level Security de Postgres (et pourquoi ce n'est pas celle de Power BI)
- •Pourquoi la RLS est le piège numéro 1 des applications générées par IA
- •Comment écrire des policies solides, avec des exemples SQL prêts à copier
- •La checklist de sécurisation que nous appliquons sur chaque projet Supabase
Sur Supabase, une table sans policy n'est pas "un peu" exposée : elle est entièrement lisible par le public.
La Row Level Security, c'est quoi exactement ?
Attention à un piège dès le départ : si vous cherchez « row level security » sur Google, la moitié des résultats parlent de Power BI. Oubliez-les. Ici, on parle de la RLS de PostgreSQL, le moteur de base de données qui alimente Supabase. Cela n'a strictement rien à voir avec le filtrage de rapports Power BI.
La Row Level Security est une fonctionnalité native de Postgres depuis la version 9.5. Le principe : au lieu de contrôler l'accès table par table, vous contrôlez l'accès ligne par ligne, en fonction de l'utilisateur qui exécute la requête.
Concrètement, une policy RLS répond à une question simple pour chaque ligne : « Est-ce que cet utilisateur a le droit de voir (ou de modifier) cette ligne précise ? »
Pourquoi c'est central sur Supabase
Supabase expose automatiquement votre base Postgres via une API REST (PostgREST) et une API temps réel. Votre front-end appelle cette API avec une clé publique (la fameuse anon key), présente en clair dans le bundle JavaScript envoyé au navigateur.
Autrement dit : votre base de données est directement accessible depuis le navigateur de vos visiteurs. La seule barrière entre un attaquant et vos données, c'est la RLS. Pas votre code React, pas vos vérifications côté client : la RLS, au niveau de la base.
Pour comprendre où la RLS s'insère dans l'architecture globale (auth, API, temps réel, storage), consultez notre guide complet sur Supabase qui détaille chaque brique de la plateforme.
Pourquoi la RLS est le piège numéro 1 des apps générées par IA
Le « vibe coding » a démocratisé la création d'applications : on décrit une idée, l'IA génère le schéma de base, le front et les appels API. En quelques minutes, une app fonctionne. Le problème : l'IA génère rarement une RLS correcte.
Voici les trois scénarios que nous voyons le plus souvent en audit :
1. La RLS n'est jamais activée
L'IA crée les tables, branche le front sur Supabase, et tout marche. Sauf que sans ENABLE ROW LEVEL SECURITY, la table est ouverte à la lecture (et parfois à l'écriture) pour n'importe qui possédant la clé anon. Comme cette clé est dans le code du navigateur, n'importe quel visiteur peut lire toute la table depuis la console.
2. Une policy trop permissive
Deuxième cas classique : l'IA active bien la RLS, mais crée une policy USING (true) pour « que ça marche ». Cette condition est toujours vraie, donc elle autorise l'accès à toutes les lignes. C'est exactement comme ne pas avoir de RLS du tout, avec l'illusion d'être protégé.
3. La clé service_role exposée
La service_role bypasse totalement la RLS (c'est son rôle : les tâches serveur de confiance). Certaines apps générées la placent dans le front-end « parce que ça débloque tout ». C'est une catastrophe : n'importe qui peut alors tout lire, tout modifier, tout supprimer.
La RLS ne dispense pas de réfléchir à la sécurité. Elle vous oblige à la penser au bon endroit : dans la base, pas dans le navigateur.
Si vous fiabilisez une application créée avec l'IA, notre guide sur le vibe coding explique comment transformer un prototype généré en produit réellement sécurisé et maintenable.
Comment écrire une policy RLS : le B.A.-BA
Sécuriser une table se fait en deux temps.
Étape 1 : activer la RLS. Tant qu'elle n'est pas activée, aucune policy ne s'applique.
alter table profiles enable row level security;Une fois activée, le comportement par défaut est « tout refuser » : plus personne n'accède aux lignes tant que vous n'avez pas défini de policy. C'est le principe du « deny by default », la bonne base de départ.
Étape 2 : créer les policies. Une policy se compose de deux clauses selon l'opération :
- •
USING (...): condition de visibilité (pour SELECT, UPDATE, DELETE). Elle filtre les lignes que l'utilisateur peut voir ou cibler. - •
WITH CHECK (...): condition de validité à l'écriture (pour INSERT, UPDATE). Elle vérifie que la nouvelle ligne respecte bien la règle.
La fonction magique de Supabase est auth.uid() : elle renvoie l'identifiant de l'utilisateur connecté (issu de son JWT). C'est le pivot de presque toutes vos policies.
-- Chaque utilisateur lit uniquement son propre profil
create policy "read own profile"
on profiles for select
to authenticated
using ( auth.uid() = id );Cette policy dit : un utilisateur authenticated ne peut lire une ligne de profiles que si l'id de la ligne correspond à son propre identifiant. Simple, mais c'est déjà toute la logique.
La RLS s'articule étroitement avec le système de connexion. Pour bien comprendre d'où vient auth.uid(), lisez notre article sur l'authentification Supabase, qui détaille les JWT, les rôles et la gestion des sessions.
Exemples de policies concrètes
Voici trois patterns que vous rencontrerez dans presque tous les projets.
Table profils : chacun gère la sienne
alter table profiles enable row level security;
create policy "read own profile"
on profiles for select
to authenticated
using ( auth.uid() = id );
create policy "update own profile"
on profiles for update
to authenticated
using ( auth.uid() = id )
with check ( auth.uid() = id );Table articles : lecture publique, écriture par le propriétaire
alter table posts enable row level security;
-- Tout le monde peut lire les articles publiés
create policy "public read published"
on posts for select
to anon, authenticated
using ( status = 'published' );
-- Seul l'auteur peut créer un article à son nom
create policy "insert own posts"
on posts for insert
to authenticated
with check ( auth.uid() = author_id );
-- Seul l'auteur peut modifier ses articles
create policy "update own posts"
on posts for update
to authenticated
using ( auth.uid() = author_id )
with check ( auth.uid() = author_id );Multi-tenant : isolation par organisation
Le cas le plus fréquent en SaaS : chaque utilisateur ne doit voir que les données de son organisation. On s'appuie sur une table de liaison plutôt que sur une simple colonne, pour éviter les fuites entre clients.
alter table documents enable row level security;
create policy "read org documents"
on documents for select
to authenticated
using (
organization_id in (
select organization_id
from memberships
where user_id = auth.uid()
)
);Astuce performance : sur les grosses tables, encapsulez ce type de sous-requête dans une fonction security definer marquée stable, et indexez les colonnes utilisées dans les policies. La RLS mal indexée est une cause fréquente de lenteurs.
Checklist de sécurisation RLS
Avant de mettre une app Supabase en production, vérifiez chaque point de cette liste.
| Point de contrôle | Ce qu'il faut vérifier |
|---|---|
| RLS activée partout | Chaque table exposée à l'API a enable row level security |
Aucune policy USING (true) | Aucune règle n'autorise l'accès à toutes les lignes sans condition |
| service_role côté serveur | La clé service_role n'apparaît jamais dans le front-end |
| WITH CHECK sur les écritures | INSERT et UPDATE valident bien la propriété de la ligne |
| Rôles explicites | Chaque policy précise to anon ou to authenticated |
| Vues et fonctions | Les vues n'exposent pas de données en contournant la RLS |
| Storage | Les buckets Supabase Storage ont aussi leurs policies |
| Tests réels | Vous avez tenté de lire les données d'un autre utilisateur, et échoué |
L'audit RLS ONDEV : ce qu'on vérifie sur chaque projet
Chez ONDEV, la RLS n'est pas une case à cocher en fin de projet : c'est une étape d'audit systématique, table par table, policy par policy.
Sur Wiloq, un SaaS de vestiaire numérique événementiel en production sur Next.js et Supabase (12+ fonctionnalités, 3 interfaces), chaque rôle (organisateur, staff, participant) dispose de policies distinctes. Un participant ne peut jamais lire les données d'un autre événement, même en manipulant l'API à la main.
Sur Swap&Share, plateforme d'échange de compétences bâtie sur React, Node et Stripe, l'isolation multi-tenant repose sur le même principe : une membership contrôle l'accès, pas une simple vérification front-end. Et sur l'application métier livrée à Dassault Aviation (90+ utilisateurs actifs), le cloisonnement des données par périmètre est audité de la même manière.
Notre méthode d'audit RLS suit trois passes :
- 1.Inventaire : lister chaque table exposée et son état RLS (activée ou non).
- 2.Analyse des policies : traquer les conditions permissives, les rôles manquants, les écritures non contrôlées.
- 3.Tests d'intrusion applicatifs : tenter concrètement d'accéder aux données d'un autre utilisateur via l'API.
Si vous confiez la mise en production à une agence Supabase qui maîtrise ces sujets, vous évitez la fuite de données qui ruine la confiance de vos utilisateurs le jour du lancement.
FAQ : Row Level Security sur Supabase
La RLS de Supabase est-elle la même que celle de Power BI ?
Si j'active la RLS, est-ce que mon application va cesser de fonctionner ?
La clé anon exposée dans mon front-end, c'est un problème de sécurité ?
anon est faite pour être publique. Ce qui protège vos données, ce n'est pas le secret de cette clé, mais vos policies RLS. En revanche, la clé service_role ne doit jamais apparaître côté client : elle contourne toute la RLS.Faut-il aussi vérifier les droits côté application ?
La RLS ralentit-elle les requêtes ?
stable. Bien conçue, la RLS a un impact négligeable.Conclusion : la RLS n'est pas une option
Sur Supabase, la Row Level Security n'est pas une fonctionnalité avancée réservée aux gros projets. C'est la barrière fondamentale entre vos données et le premier visiteur curieux. Une table sans policy correcte, et c'est toute votre base qui devient publique, y compris les apps générées à la va-vite avec l'IA.
La bonne nouvelle : quelques policies bien écrites, une checklist rigoureuse et un vrai test d'accès croisé suffisent à passer d'une base grande ouverte à une base réellement cloisonnée.
Vous lancez un projet Supabase ou vous avez un doute sur la sécurité d'une app existante ? Parlons de votre audit RLS : nous vérifions vos policies table par table avant que vos données ne se retrouvent exposées.


