Aller au contenu

Votre appli Supabase est-elle sûre ?

Supabase peut-il héberger de vraies données ? Oui, et il est fait pour être interrogé depuis un navigateur. C'est pourquoi deux réglages décident de tout.

Vlad Tkachenko5 min de lecture
La carte de vérification de sécurité de Reeve pour les applis Supabase, avec le logo Supabase sur une tuile blanche.

Les logos sont la propriété de leurs détenteurs respectifs et servent uniquement à indiquer la compatibilité.

En bref

  • Supabase peut héberger de vraies données d'utilisateurs, et il est fait pour être interrogé directement depuis un navigateur. C'est exactement pour cela que les règles sur vos tables font tout le travail.
  • La clé publiable a sa place dans votre appli. sb_secret_… et service_role contournent toutes les règles que vous avez écrites.
  • Les tables créées dans le Table Editor reçoivent Row Level Security automatiquement. Celles créées en exécutant du SQL non.

Supabase vous donne une vraie base Postgres avec une API déjà posée devant, et c'est pourquoi une appli peut parler à des données réelles vingt minutes après avoir commencé. Ce qui surprend les gens plus tard, c'est que cette même API est joignable par n'importe qui, depuis n'importe où, avec des identifiants imprimés à l'intérieur de votre appli.

Voici ce que guide après guide raconte de travers : ce n'est pas un défaut, et le cacher n'est pas la solution. Supabase est conçu pour être interrogé directement depuis un navigateur. La protection a toujours été prévue ailleurs, et savoir où est l'essentiel de ce qu'il y a à savoir pour faire tourner une appli Supabase sereinement.

Pourquoi votre base de données est sur internet exprès

Parce que votre appli lui parle depuis le navigateur de votre visiteur, pas depuis un serveur que vous exploitez.

Voyez cela comme une boutique. Votre appli est la devanture, remise en entier à chaque visiteur. Votre base de données est la réserve, et avec Supabase, la réserve a délibérément sa propre porte donnant sur la rue, pour que votre devanture puisse s'y servir sans service de livraison entre les deux. C'est cette porte qui vous évite d'écrire un backend.

Ce qui veut dire que la porte est publique, et que son adresse est dans votre appli parce que votre appli doit y frapper. Il n'existe aucun arrangement où cette adresse reste secrète. La question n'a donc jamais été « des inconnus peuvent-ils atteindre ma base ». Ils le peuvent, par conception. La question est ce qu'elle leur remet quand ils demandent.

La clé Supabase dans mon appli est-elle censée y être ?

L'une des deux, oui. L'autre jamais, et elles se ressemblent presque trait pour trait.

Les deux s'appellent des clés API. Une seule a jamais été faite pour être lue.

La clé publiable (sb_publishable_… dans les projets récents, anon dans les anciens) indique à quel projet appartient une requête. Elle ne porte aucun privilège propre, ce qui est pourquoi la documentation de Supabase la décrit comme sûre à intégrer dans des pages web et des applis mobiles. La trouver dans votre appli n'est pas un problème.

La clé secrète, sb_secret_… ou l'ancienne service_role, est l'inverse. Elle contourne entièrement vos règles et lit et écrit chaque ligne de chaque table, depuis n'importe où. Sa place est sur un serveur, dans une edge function, dans un worker : nulle part où un navigateur peut aller.

Elles sont côte à côte sur la même page du tableau de bord et ont la même forme. Si l'une a déjà été collée dans du code frontend, renouvelez-la dans le tableau de bord avant de modifier quoi que ce soit, parce que supprimer la ligne ne ferme pas la porte.

Cette page, c'est Settings puis API Keys, et elle porte quatre valeurs plutôt que deux.

Le réglage qui décide de ce que la porte remet

Row Level Security : un interrupteur par table qui décide, ligne par ligne, qui peut lire quoi. C'est tout ce qui rend une clé publiable sans danger.

Votre appli et un inconnu frappent à la même porte. C'est le réglage qui décide qui entre, pas les écrans de votre appli.

Désactivé, cette clé renvoie la table entière à quiconque la demande. Activé, avec une politique écrite, la base elle-même filtre chaque requête, y compris celles qui ne sont jamais passées par votre appli.

Deux détails décident si vous l'avez vraiment, et aucun n'est visible depuis votre appli :

Comment la table a été créée. Supabase active Row Level Security automatiquement pour les tables faites dans le Table Editor du tableau de bord. Les tables créées en exécutant du SQL ne l'obtiennent pas et doivent être activées délibérément. Fichiers de migration, scripts et schémas générés par IA créent tous les tables en exécutant du SQL, donc un projet construit ainsi peut avoir une rangée de tables non protégées qui ressemblent exactement aux tables protégées.

Ce que dit la politique. Activé veut dire fermé jusqu'à ce qu'une politique l'ouvre. Une politique qui autorise tout le monde l'ouvre en grand pendant que le tableau de bord annonce toujours la table comme ayant Row Level Security activé, l'état qui a l'air protégé et ne l'est pas.

Le stockage est encore à part. Un bucket public est listable et téléchargeable par quiconque connaît l'adresse de votre projet, quoi que disent vos règles de tables.

Comment vérifier votre projet Supabase en une dizaine de minutes

Authentication → Policies. Lisez toute la liste. Toute table affichant Row Level Security comme désactivé est lisible par n'importe qui. Pour celles qui l'affichent comme activé, ouvrez la politique et lisez ce qu'elle autorise réellement.

Settings → API. Confirmez que la clé embarquée par votre appli est la clé publiable. Si une clé secrète a un jour été dans du code frontend, renouvelez-la ici d'abord. Si votre tableau de bord affiche des clés commençant par sb_publishable_ et sb_secret_ plutôt que anon et service_role, c'est le format plus récent, et la même règle décide laquelle des deux a sa place dans votre appli.

Storage → Buckets. Vérifiez lesquels sont publics, et si c'est bien ce que vous vouliez pour les fichiers qui s'y trouvent.

Puis regardez depuis l'extérieur. Tout ce qui précède est ce que votre tableau de bord déclare configuré. Ce qu'une requête anonyme récupère vraiment est une autre question, et c'est celle à laquelle répond notre scan gratuit : il interroge comme le ferait un inconnu, sans lire la moindre de vos lignes, et vous donne une note en une vingtaine de secondes : voir ce que votre appli expose.

Que faire

  • Votre API Supabase est publique exprès. La protection, ce sont les règles sur vos tables, jamais le secret de l'adresse.
  • La clé publiable a sa place dans votre appli. sb_secret_… et service_role jamais, et une clé secrète divulguée ignore toutes les règles que vous avez écrites.
  • Les tables faites dans le Table Editor reçoivent Row Level Security automatiquement. Celles créées en exécutant du SQL non.
  • Activé n'est pas restreint. Lisez la politique, pas seulement le bouton.
  • Les buckets de stockage ont leurs propres réglages, donc des tables verrouillées ne disent rien de vos fichiers.

Ouvrez Authentication → Policies et parcourez la liste une fois. Les tables marquées désactivé sont celles par lesquelles commencer, et si vous préférez traverser toute la surface sous forme de liste, la checklist sécurité en 10 minutes en est la version courte. Quoi que vous trouviez, savoir que vous pouvez remettre les données compte autant que les verrouiller, et cela dépend entièrement de ce que vous sauvegardez.

Si vous préférez que cela ne dépende pas de votre mémoire, voici comment fonctionnent les sauvegardes Supabase automatiques.

Ce qui peut réellement mal tourner avec Supabase

Rien de tout cela ne signifie que vous avez fait une erreur : ce sont les failles habituelles quand on avance vite. Voici ce qui vaut la peine d'être vérifié :

  • Row Level Security (RLS) désactivée

    Le RLS est la règle de Supabase qui détermine qui peut lire ou modifier chaque ligne d'une table. Avec la clé publique « anon » (qui est censée être dans votre appli), n'importe qui peut interroger directement votre base de données. Le RLS est ce qui l'empêche de voir des lignes qui ne lui appartiennent pas. S'il est désactivé, une table peut être entièrement lisible, voire modifiable, par tous. C'est le réglage Supabase le plus important, et Reeve le vérifie en comptant les lignes, jamais en les lisant.

  • Une clé service_role qui a fuité

    Supabase vous donne deux clés. La clé « anon » est publique par conception et sûre dans le navigateur. La clé « service_role » contourne toutes vos règles de sécurité et ne doit vivre que sur un serveur. Si elle se retrouve un jour dans le code front-end de votre appli, quelqu'un peut faire n'importe quoi avec vos données. Reeve décode les clés qu'il trouve et vous dit exactement laquelle est exposée : la « anon » sûre reçoit une coche verte, « service_role » est une alerte rouge.

  • Espaces de stockage publics

    Les fichiers que les gens téléversent vivent dans des « espaces » (buckets) de Supabase Storage. Un espace réglé sur public signifie que n'importe qui peut lister et télécharger ce qu'il contient, et les téléversements privés peuvent donc devenir visibles par tous. Reeve vérifie si vos espaces sont listables ; il ne télécharge jamais les fichiers de qui que ce soit.

  • Votre API ouverte à n'importe quel site (CORS)

    Supabase donne à votre base de données une adresse web (via PostgREST). Combinée à un réglage de partage trop permissif, un autre site pourrait appeler vos données depuis le navigateur d'un visiteur. Reeve vérifie si vos points d'accès répondent aux inconnus et à d'autres sites, sans jamais s'en servir pour modifier quoi que ce soit.

  • Tables et points d'accès exposés sans règles

    Chaque table que vous créez est accessible via l'API de Supabase ; c'est voulu, et le RLS est censé la garder. Mais une nouvelle table ajoutée à la hâte, avant que ses règles ne soient définies, peut être brièvement (ou durablement) ouverte. Reeve vérifie ce qui est réellement accessible depuis l'extérieur.

  • Clés ou configuration laissées dans l'appli déployée

    Au-delà des propres clés de Supabase, les applis transportent souvent d'autres réglages et secrets dans leur code front-end ou dans un .env exposé. Reeve lit le code chargé de votre appli et vérifie les fichiers de configuration accessibles, puis vous dit quelles valeurs sont sûres à rendre publiques et lesquelles ne le sont pas.

Ce que Reeve est, et ce qu'il n'est pas

Reeve est une vérification gratuite, en lecture seule, depuis l'extérieur, comme un inspecteur qui essaie les portes sans entrer. C'est rapide et ça repère les erreurs courantes à fort impact. Ce n'est pas un audit de sécurité complet, et une note propre n'est pas une garantie. Elle signifie que les portes évidentes sont fermées. Tout ce que fait Reeve est passif : il compte les lignes plutôt que de les lire, et ne télécharge jamais vos fichiers.

Supabase vous donne de vrais outils de sécurité (un Security Advisor et un linter de base de données qui signalent les problèmes de RLS et d'exposition directement dans le tableau de bord), et ils valent vraiment la peine d'être utilisés. Ce que Reeve ajoute : la plupart des gens qui construisent sur Supabase vivent dans leur créateur d'applis, pas dans l'éditeur SQL, et le conseiller parle le langage des développeurs. Reeve vérifie toute votre appli depuis l'extérieur, comme un attaquant atteindrait vos données, et explique ce qu'il trouve en mots simples. Et si vous préférez ne pas la surveiller vous-même, nous le pouvons.

Vous voulez que ce soit géré, pas seulement vérifié ?

Reeve Care continue de surveiller votre appli, sauvegarde vos données et vous aide à réparer les choses quand elles cassent, pour que vous puissiez continuer à créer au lieu de vous inquiéter.

En savoir plus sur Reeve Care

FAQ

Qu'est-ce que le RLS de Supabase et en ai-je vraiment besoin ?

Le RLS (Row Level Security) décide qui peut voir ou modifier chaque ligne de vos tables. Comme votre appli expédie une clé publique « anon » capable d'interroger directement la base de données, le RLS est ce qui empêche les données d'un utilisateur d'être visibles par tous. Oui : pour toute table contenant de vraies données, vous en avez besoin. Reeve vérifie s'il est activé, sans lire vos données.

La clé anon de Supabase est-elle sûre à exposer ?

Oui. La clé « anon » est conçue pour vivre dans votre front-end, et à elle seule elle ne fait que ce que vos règles RLS autorisent. La clé qui ne doit jamais être exposée est la clé « service_role », qui ignore toutes les règles. Reeve décode les clés de votre appli et vous dit laquelle est laquelle.

Que se passe-t-il si ma clé service_role fuite ?

La clé service_role contourne toutes les règles de sécurité, donc quiconque la possède peut lire, modifier ou supprimer toutes vos données. Si elle est dans votre code front-end, considérez-la comme compromise : renouvelez-la dans le tableau de bord Supabase et déplacez-la vers un serveur. Reeve signale une clé service_role exposée comme un problème critique.

Reeve peut-il vérifier mon Supabase sans mon mot de passe de base de données ?

Oui. Reeve n'utilise que ce que votre appli expose déjà publiquement : la même clé anon et les mêmes points d'accès que le navigateur de n'importe quel visiteur utilise. Il n'a jamais besoin de votre mot de passe de base de données, ne se connecte jamais en tant qu'administrateur et ne lit ni ne télécharge jamais vos lignes ou fichiers.

Pourquoi Supabase laisse-t-il un navigateur parler à ma base de données ?

Parce que c'est le produit. Supabase met une API devant Postgres pour que votre appli puisse interroger des données sans que vous écriviez et hébergiez un backend, et c'est ce qui rend la construction si rapide. La sécurité ne vient pas du fait de cacher cette API, qu'on ne peut pas cacher. Elle vient de Postgres qui refuse de renvoyer les lignes auxquelles le visiteur n'a pas droit.

Activer Row Level Security sur une table la rend-il privée ?

Cela la rend fermée jusqu'à ce que vous écriviez une politique, ce qui est le bon point de départ. Mais une politique qui autorise tout le monde la rouvre, pendant que le tableau de bord affiche toujours la table comme ayant Row Level Security activé. Activé et restreint sont deux états différents, et un seul se voit d'un coup d'œil.

Quelles tables risquent le plus d'être non protégées ?

Celles créées en exécutant du SQL plutôt qu'en cliquant dans le Table Editor : fichiers de migration, scripts, et schémas écrits pour vous par un builder IA. Le Table Editor active Row Level Security automatiquement. Le SQL non, et rien ne signale la différence ensuite.

Mon stockage Supabase est-il couvert par Row Level Security ?

Le stockage a ses propres réglages, donc une base verrouillée ne vous dit rien de vos fichiers. Un bucket marqué public peut être listé et téléchargé par quiconque connaît l'adresse de votre projet, que votre appli renvoie ou non vers ce qu'il contient.

Écrit par

Vlad Tkachenko

Fondateur de Reeve

Je passe mes journées à examiner des applications créées avec Lovable, Bolt, v0, Cursor et Replit, et la courte liste d'erreurs qui y reviennent sans cesse.

En savoir plus sur l'auteur

Vous avez créé votre appli dans un outil précis ? Voici le même topo honnête pour :

← Voir tous les guides de sécurité des créateurs

Vérification externe automatisée, pas un audit complet. L'absence de problème n'est pas une garantie de sécurité.