Aller au contenu

Bases de la sécurité

Quelles clés API sont sûres côté navigateur, et lesquelles non

Votre clé anon Supabase est faite pour être publique. Votre clé service_role non, et elle ignore toutes les règles que vous posez. Comment les distinguer.

Vlad Tkachenko7 min de lecture

En bref

  • Trouver une clé API dans le code de votre application n'est pas automatiquement un problème. Certaines clés sont faites pour y être.
  • Les clés publiables sont sûres dans le navigateur. Les clés secrètes non : une clé secrète côté navigateur, c'est une caisse ouverte.
  • Deux vérifications les séparent en moins d'une minute : lire le préfixe et, sur une ancienne clé Supabase, décoder le rôle.

Quand on a créé son application avec Lovable, Bolt, v0, Cursor ou Replit, il arrive tôt ou tard que quelqu'un ouvre le site, appuie sur F12 et annonce que votre clé API est « exposée ». Pour une application dont on ne lit pas le code soi-même, la nouvelle a de quoi inquiéter.

Voici ce que guide après guide présente de travers : certaines de ces clés sont faites pour être là. Traiter chaque clé visible comme une fuite conduit soit à paniquer pour rien, soit, bien pire, à apprendre à ignorer l'avertissement, et à l'ignorer aussi le jour où il compte vraiment.

Est-ce grave que ma clé API soit visible ?

En général non. Tout dépend de la clé dont il s'agit.

Chaque service qui parle à un navigateur distribue deux sortes d'identifiants. L'une est une adresse. L'autre est un trousseau de clés du bâtiment. Les deux s'appellent « clé API », et c'est là l'essentiel de la confusion.

Une adresse peut être publiée sans risque. Elle indique à quel projet appartient une requête, rien de plus ; la vérification des droits se fait ailleurs. Un trousseau ne le peut pas, parce qu'il est la vérification des droits : qui le détient peut faire tout ce qu'il autorise, depuis n'importe où.

Votre application a besoin de l'adresse dans le navigateur pour fonctionner. Elle ne devrait jamais y avoir besoin du trousseau.

Pourquoi votre application envoie des clés au navigateur

Parce que la requête part du navigateur de votre visiteur, pas de votre serveur.

Quand votre application charge la liste des commandes de vos utilisateurs, cette requête part directement du navigateur du visiteur vers votre fournisseur de base de données. Elle doit indiquer à quel projet elle appartient, et cet identifiant doit se trouver dans la page, puisque c'est de là que part la requête.

Il n'existe aucune version où cet identifiant reste secret. Il parvient à chaque visiteur, par conception. C'est exactement pour cela que les fournisseurs coupent leurs identifiants en deux : ils savent que l'un des deux sera public, alors ils l'ont rendu inoffensif.

La sécurité ne vient pas du fait de cacher l'adresse. Elle vient des règles posées à l'autre bout : chez Supabase, Row Level Security, qui décide ligne par ligne qui a le droit de voir quoi. Ce sont ces règles qui méritent d'être vérifiées, et les activer n'est pas la même chose qu'être protégé.

C'est Row Level Security qui rend la clé anon sans danger. Une clé service_role passe outre.

Les deux familles de clés

FournisseurCléSûre dans le navigateur ?Ce qu'elle fait
Supabasesb_publishable_…, ou anon sur les anciens projetsÀ sa placeIndique de quel projet il s'agit. Chaque requête reste filtrée par vos règles Row Level Security.
Supabasesb_secret_…, ou service_role sur les anciens projetsJamaisContourne entièrement Row Level Security. Lit et écrit chaque ligne de chaque table, quelles que soient vos règles.
Stripepk_live_… (publiable)À sa placeCrée les formulaires de paiement. Ne peut ni déplacer d'argent ni lire les clients.
Stripesk_live_… (secrète)JamaisAccès complet au compte : paiements, remboursements, virements, fiches clients.
OpenAI / Anthropictoute clé APIJamaisIl n'existe pas de variante publiable. Chaque clé facture directement votre compte.

Le schéma vaut au-delà de ces trois-là. Si un fournisseur ne propose qu'une seule sorte de clé, considérez qu'elle est secrète et qu'elle appartient à un serveur.

Les distinguer en 60 secondes

Pour Stripe, et la plupart des fournisseurs, lisez le préfixe. pk_ est publiable et sans danger. sk_ est secrète et ne l'est pas. Certains fournisseurs glissent _test_ ou _live_ au milieu : une clé de test divulguée est un problème bien plus petit qu'une clé de production, mais renouvelez les deux.

Pour Supabase, cela dépend de l'âge de votre projet. Supabase a émis deux formes de clés différentes, et les deux circulent aujourd'hui dans des applications en service.

Projets récents : lisez le préfixe, exactement comme chez Stripe.sb_publishable_… est celle qui a sa place dans votre application. sb_secret_… est celle à renouveler aujourd'hui. Il n'y a rien à décoder : ce à quoi sert la clé est écrit devant. Ce qui a changé, et ce que cela veut dire pour votre application, si vous ne les avez pas encore croisées.

Anciens projets : il faut regarder à l'intérieur de la clé. La paire d'origine, anon et service_role, ce sont des JWT : trois blocs de charabia séparés par des points, dont celui du milieu est de l'information lisible, pas du chiffrement. Le rôle de la clé y est écrit en clair.

Aucun outil n'est nécessaire dans un cas comme dans l'autre. Ouvrez Settings → API Keys dans le tableau de bord Supabase : il vous dit laquelle est laquelle. Si vous préférez vérifier la clé que vous avez réellement trouvée dans votre application, la section du milieu d'une ancienne clé se décode en quelque chose comme ceci.

{
  "iss": "supabase",
  "ref": "abcdefghij…",
  "role": "anon",          ← c'est ce mot qui compte
  "iat": 1750000000
}
Sur une ancienne clé, la section du milieu est du texte lisible, pas du chiffrement. Un seul mot y décide si la clé pouvait être publiée.

"role": "anon" est la bonne. "role": "service_role" est celle à renouveler aujourd'hui. Sur une ancienne clé, ce seul mot fait toute la différence, et c'est pourquoi un analyseur qui se contente de repérer des chaînes en forme de clé vous donne du bruit plutôt qu'une réponse : il ne peut pas vous dire laquelle de deux clés identiques en apparence vous avez réellement publiée.

Si vous préférez ne pas passer votre application clé par clé, notre scan gratuit lit votre site en ligne et vous dit lesquelles de ces clés se voient depuis l'extérieur. Cela prend une vingtaine de secondes et ne demande aucun compte : scanner votre application.

Ce qui se passe vraiment quand une clé secrète fuit

Chaque ligne de votre base de données devient lisible et modifiable par celui qui a trouvé la clé, y compris des tables que vous n'avez jamais exposées à votre application et les données personnelles de vos utilisateurs. Row Level Security ne s'applique pas à une clé secrète Supabase (sb_secret_…, ou service_role sur un ancien projet). C'est la raison d'être de cette clé.

Le dommage n'est pas théorique non plus. On le découvre généralement par un message d'assistance à propos de données qui ont changé toutes seules, ou par une table soudain vide.

Une clé sk_live_ Stripe divulguée signifie remboursements, paiements et fiches clients. Une clé de fournisseur d'IA divulguée signifie une facture, parfois très lourde, qui arrive avant que quiconque ne s'en aperçoive.

Rien de tout cela ne demande un attaquant sophistiqué. Des robots parcourent les sites publics à la recherche exactement de ces chaînes, et ils n'ont pas besoin de savoir qui vous êtes pour trouver la vôtre.

Si vous voulez la version propre à la plateforme de ce qu'il faut vérifier, nous avons un guide en langage clair pour les applications Supabase.

Que faire maintenant

Que faire

  • Repérez chaque clé dans votre application et identifiez-la. Le préfixe pour Stripe et pour les clés Supabase récentes ; le champ role à l'intérieur des anciennes clés Supabase.
  • Si vous trouvez une clé secrète côté navigateur, renouvelez-la d'abord. La supprimer de votre code ne ferme pas la porte : l'ancienne valeur existe toujours dans votre historique de versions et dans les copies en cache de votre site.
  • Déplacez sur un serveur ce qui avait besoin de cette clé : une edge function, une route serverless, n'importe quoi qui ne soit pas le navigateur.
  • Activez Row Level Security sur chaque table, puis vérifiez qu'elle fonctionne réellement. Une clé publiable (sb_publishable_… ou anon) n'est sûre que grâce à ces règles ; sans elles, elle lit toute votre base.
  • Vérifiez la facturation et les journaux après toute exposition d'une clé secrète. Le renouvellement arrête la suite, pas ce qui a déjà eu lieu.

Si vous préférez avancer sous forme de liste, la checklist sécurité en 10 minutes couvre ce point et les autres choses à désactiver dans une application fraîchement lancée.

Et si une fuite finit par vider une table, la récupérer dépend entièrement de ce que vous sauvegardiez.

FAQ

On me dit que ma clé API est exposée. Dois-je paniquer ?

Pas avant de savoir de quelle clé il s'agit. Si elle commence par pk_ ou s'il s'agit d'une clé anon Supabase, elle est faite pour être publique et tout va bien. Si elle commence par sk_ ou s'il s'agit d'une clé service_role, renouvelez-la immédiatement, puis regardez ce à quoi elle donnait accès.

Puis-je simplement cacher la clé pour que personne ne la trouve ?

Non. Tout ce que votre navigateur peut utiliser, un visiteur peut le lire : minifier, renommer ou obscurcir ne fait gagner que quelques secondes. La solution n'est jamais de cacher une clé secrète côté navigateur, mais de la déplacer sur un serveur, ou d'utiliser une clé publiable qu'il était sans danger d'exposer dès le départ.

Pourquoi Supabase me donne-t-il une clé que tout le monde peut lire ?

Parce que ce n'est pas la clé anon qui protège vos données. Elle indique seulement à quel projet vous parlez. La vraie protection, c'est Row Level Security, qui décide ligne par ligne ce que chaque visiteur a le droit de voir. C'est pourquoi une clé anon avec RLS activé ne pose aucun problème, et la même clé sans RLS est une base de données ouverte.

Ma clé Supabase commence par sb_publishable_. Est-ce la même chose que la clé anon ?

Elle joue le même rôle. Supabase a renommé ses clés : sb_publishable_ a pris la suite de la clé anon, et sb_secret_ celle de service_role. Une clé qui commence par sb_publishable_ est donc faite pour vivre dans votre application, et une clé qui commence par sb_secret_ ne l'est jamais. Les anciens projets portent toujours les clés anon et service_role d'origine, et elles fonctionnent encore ; vous pouvez même voir les deux paires côte à côte dans votre tableau de bord.

J'ai déjà collé une clé secrète dans mon application. Et maintenant ?

Renouvelez-la d'abord : dans le tableau de bord du fournisseur, générez une nouvelle clé et révoquez l'ancienne. C'est cela qui ferme réellement la porte ; la retirer de votre code ne suffit pas, car l'ancienne valeur reste dans votre historique et dans les copies en cache. Déplacez ensuite sur un serveur ce qui avait besoin de cette clé, et vérifiez votre facturation et vos journaux pour repérer ce que vous n'avez pas fait.

É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

À lire ensuite

Vous ne savez pas où en est votre propre application ?

Lancez une analyse gratuite et obtenez une note claire de A à F en une vingtaine de secondes. Sans compte, sans carte.

Analyser mon application

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