Que fait supabase ?
Principes Fondamentaux
1. Supabase évolue fréquemment — vérifiez toujours le journal des modifications et la documentation actuelle avant d'implémenter.
Ne vous fiez pas aux données d'entraînement pour les fonctionnalités Supabase. Les signatures de fonctions, les paramètres config.toml et les conventions d'API changent entre les versions.
Commencez par récupérer https://supabase.com/changelog.md (un index léger des résumés — pas un téléchargement lourd), recherchez les balises breaking-change pertinentes pour votre tâche et suivez la page liée pour toute mise à jour. Ensuite, consultez le sujet concerné via les méthodes d'accès à la documentation ci-dessous.
2. Vérifiez votre travail. Après avoir appliqué une correction, exécutez une requête de test pour confirmer que le changement fonctionne. Une correction sans vérification est incomplète.
3. Récupérez les erreurs, ne bouclez pas. Si une approche échoue après 2 à 3 tentatives, arrêtez-vous et reconsidérez-la. Essayez une autre méthode, consultez la documentation, examinez l'erreur plus attentivement et, si possible, vérifiez les journaux pertinents. Les problèmes Supabase ne se résolvent pas toujours en répétant la même commande, et la réponse n'est pas toujours dans les journaux, mais il vaut souvent la peine de les consulter avant de continuer.
4. Exposition des tables à l'API de données : Selon les paramètres de l'API de données de l'utilisateur, les tables nouvellement créées peuvent ne pas être automatiquement exposées via l'API REST. Dans ce cas, il faudra accorder explicitement les droits aux rôles anon et authenticated.
Notez que cela est distinct de la RLS, qui contrôle quelles lignes sont visibles une fois la table accessible, et non si la table est accessible du tout.
Lorsqu'un utilisateur signale qu'une table créée par SQL est soudainement inaccessible, vérifiez ses paramètres d'API de données et si les rôles ont obtenu l'accès via une instruction SQL GRANT explicite. Lorsque vous accordez un accès public (anon/authenticated), activez toujours la RLS. Voir Exposer une table à l'API de données pour la procédure complète.
5. RLS dans les schémas exposés.
Activez la RLS sur chaque table de tout schéma exposé, ce qui inclut public par défaut. C'est crucial dans Supabase car les tables des schémas exposés peuvent être accessibles via l'API de données lorsque les rôles anon/authenticated y ont accès (voir Exposer une table à l'API de données). Pour les schémas privés, préférez la RLS comme défense en profondeur. Après avoir activé la RLS, créez des politiques correspondant au modèle d'accès réel plutôt que d'appliquer par défaut le même motif auth.uid() à chaque table.
6. Checklist de sécurité. Lorsque vous travaillez sur une tâche Supabase touchant à l'authentification, la RLS, les vues, le stockage ou les données utilisateur, parcourez cette checklist. Il s'agit de pièges de sécurité propres à Supabase qui créent silencieusement des vulnérabilités :
-
Sécurité de l'authentification et des sessions
- N'utilisez jamais les revendications
user_metadatadans les décisions d'autorisation basées sur JWT. Dans Supabase,raw_user_meta_dataest modifiable par l'utilisateur et peut apparaître dansauth.jwt(), il est donc dangereux pour les politiques RLS ou toute autre logique d'autorisation. Stockez les données d'autorisation dansraw_app_meta_data/app_metadataà la place. - Supprimer un utilisateur n'invalide pas ses jetons d'accès existants. Déconnectez-le ou révoquez d'abord ses sessions, gardez une durée de validité courte pour les JWT des applications sensibles, et pour des garanties strictes, validez
session_idpar rapport àauth.sessionspour les opérations sensibles. - Si vous utilisez
app_metadataouauth.jwt()pour l'autorisation, rappelez-vous que les revendications JWT ne sont pas toujours fraîches tant que le jeton de l'utilisateur n'est pas actualisé.
- N'utilisez jamais les revendications
-
Exposition des clés API et du client
- N'exposez jamais la clé
service_roleou la clé secrète dans les clients publics. Préférez les clés publiables pour le code frontend. Les clésanonhéritées ne sont là que pour la compatibilité. Dans Next.js, toute variable d'environnementNEXT_PUBLIC_est envoyée au navigateur.
- N'exposez jamais la clé
-
RLS, vues et code de base de données privilégié
- Les vues contournent la RLS par défaut. Dans Postgres 15 et versions ultérieures, utilisez
CREATE VIEW ... WITH (security_invoker = true). Dans les versions antérieures de Postgres, protégez vos vues en révoquant l'accès aux rôlesanonetauthenticated, ou en les plaçant dans un schéma non exposé. - UPDATE nécessite une politique SELECT. Dans la RLS Postgres, une opération UPDATE doit d'abord SELECT la ligne. Sans politique SELECT, les mises à jour renvoient silencieusement 0 ligne — pas d'erreur, mais aucun changement.
auth.role()est obsolète — utilisez plutôt la clauseTO. Supabase a renduauth.role()obsolète en faveur de la spécification directe du rôle cible sur la politique avecTO authenticatedouTO anon. Au-delà de l'obsolescence,auth.role() = 'authenticated'échoue silencieusement lorsque les connexions anonymes sont activées, car les utilisateurs anonymes portent le rôle Postgresauthenticatedet réussissent la vérification, que l'utilisateur soit réellement connecté ou non.-- Obsolète (ne pas utiliser) create policy "exemple" on table_name for select using ( auth.role() = 'authenticated' );TO authenticatedseul est une authentification sans autorisation (BOLA / IDOR). UtiliserTO authenticatedne vérifie que le rôle — cela ne limite pas les lignes auxquelles un utilisateur peut accéder. Le modèle correct combineTO authenticatedavec un prédicat de propriété dansUSING:create policy "exemple" on table_name for select to authenticated using ( (select auth.uid()) = user_id );- Les politiques UPDATE nécessitent à la fois
USINGetWITH CHECK. SansWITH CHECK, un utilisateur peut réaffecter leuser_idd'une ligne à un autre utilisateur :create policy "exemple" on table_name for update to authenticated using ( (select auth.uid()) = user_id ) with check ( (select auth.uid()) = user_id ); - Les fonctions
SECURITY DEFINERcontournent la RLS. Une fonctionSECURITY DEFINERs'exécute avec les privilèges de son créateur — généralement un rôle avecbypassrls(par ex.,postgres). N'ajoutez jamaisSECURITY DEFINERpour résoudre une erreur de permission ; cela supprime silencieusement le contrôle d'accès sans corriger la cause sous-jacente. PréférezSECURITY INVOKER. - Les fonctions
SECURITY DEFINERdanspublicsont appelables par tous les rôles. Postgres accordeEXECUTEàPUBLICpar défaut pour toute nouvelle fonction, donc toute fonctionSECURITY DEFINERdanspublicest un point d'accès API public appelable paranonetauthenticated(qui héritent dePUBLIC) sans aucune autorisation supplémentaire. LorsqueSECURITY DEFINERest vraiment nécessaire (par ex., pour contourner la RLS sur une table de recherche interne), gardez la fonction dans un schéma non exposé, incluez toujours une vérificationauth.uid()dans le corps de la fonction, et exécutezsupabase db advisorsaprès les modifications.
- Les vues contournent la RLS par défaut. Dans Postgres 15 et versions ultérieures, utilisez
-
Contrôle d'accès au stockage
- Upsert du stockage nécessite INSERT + SELECT + UPDATE. Accorder uniquement INSERT permet de nouveaux téléversements, mais le remplacement de fichier (upsert) échoue silencieusement. Les trois privilèges sont nécessaires.
-
Sécurité des dépendances et de la chaîne d'approvisionnement
- Épinglez toujours les versions des paquets et validez les lockfiles lors de l'installation des paquets Supabase (
supabase-js,@supabase/ssr,supabase-py, etc.). Voir le guide de sécurité npm pour la checklist complète.
- Épinglez toujours les versions des paquets et validez les lockfiles lors de l'installation des paquets Supabase (
Pour tout problème de sécurité non couvert ci-dessus, récupérez l'index de sécurité des produits Supabase : https://supabase.com/docs/guides/security/product-security.md