Données6 min de lecture

Sécuriser une application Supabase avant sa mise en production

Le protocole d'audit pratique en 9 étapes pour vérifier l'étanchéité de votre base de données, la gestion des secrets et les autorisations avant de déployer.

Créer une application avec Supabase et un outil de vibe coding (Cursor, Lovable, Bolt) permet de prototyper un produit complet en un temps record. Cependant, la mise à disposition d'une interface directe avec PostgreSQL via PostgREST implique que chaque table exposée devient une API publique potentielle.

Ce guide détaille une méthode structurée en 9 étapes concrètes pour auditer votre projet Supabase avant son ouverture aux utilisateurs réels.

1. Cartographier les données et l'ownership

La première démarche consiste à classifier la sensibilité de chaque table de votre schéma public :

  • Données publiques : Articles de blog, catalogue de produits publics, configurations générales accessibles en lecture anonyme.
  • Données privées liées à un compte : Profils utilisateurs, documents personnels, paniers d'achat, historiques de commande.
  • Données sensibles ou administratives : Factures, abonnements Stripe, journaux d'audit, colonnes de rôles (role, is_admin).

Pour chaque table contenant des données privées, identifiez clairement la colonne qui établit la propriété de la ressource (généralement user_id uuid references auth.users(id) ou workspace_id).

2. Vérifier l'activation et les politiques RLS

Pour chaque table de votre base de données :

  1. Vérifier l'activation effective : Assurez-vous que RLS est formellement activé. Si vous déclarez des politiques sur une table sans exécuter ALTER TABLE public.nom_table ENABLE ROW LEVEL SECURITY;, PostgreSQL ignore les politiques et laisse la table ouverte.
  2. Distinguer les opérations : Évitez les politiques génériques FOR ALL. Définissez des politiques distinctes pour SELECT, INSERT, UPDATE et DELETE.
  3. Contrôler la clause USING et WITH CHECK : Assurez-vous que l'écriture empêche l'usurpation d'identité en vérifiant systématiquement WITH CHECK (auth.uid() = user_id).

Pour approfondir le fonctionnement exact de ces clauses et éviter les faux sentiments de sécurité, consultez notre Wiki sur le Row Level Security Supabase.

3. Vérifier la gestion des clés et l'étanchéité des secrets

La configuration des identifiants Supabase conditionne l'ensemble de votre sécurité :

  • Clé publique anon : Destinée au frontend (NEXT_PUBLIC_SUPABASE_ANON_KEY), elle est publique par conception. Sa sécurité dépend exclusivement de vos politiques RLS.
  • Clé privée service_role : Cette clé utilise le rôle PostgreSQL service_role qui possède l'attribut BYPASSRLS. Elle permet d'effectuer des tâches d'administration en contournant le filtrage des lignes. Elle ne doit être présente que dans vos variables d'environnement serveur protégées (SUPABASE_SERVICE_ROLE_KEY) et ne doit jamais être exposée dans un composant client.
  • Chaîne de connexion directe (Database URL) : Ne stockez jamais le mot de passe administrateur de votre base de données dans le code de votre application.

Pour comprendre comment inspecter votre bundle compilé et éviter les fuites de clés sensibles, consultez notre Wiki sur les secrets exposés côté navigateur.

4. Auditer l'authentification et les redirections

L'authentification gérée par Supabase Auth requiert plusieurs points d'attention :

  • Validation des URLs de redirection (Redirect URLs) : Dans le dashboard Supabase (Authentication > URL Configuration), supprimez les jokers trop permissifs (comme *) et ne conservez que vos domaines de production et de pré-production légitimes afin d'empêcher les attaques par vol de jeton d'authentification lors des réinitialisations de mot de passe ou des flux OAuth.
  • Énumération de comptes : Activez l'option d'obfuscation des erreurs d'authentification pour éviter qu'un tiers ne puisse tester l'existence d'adresses email enregistrées sur votre plateforme.

5. Contrôler les fonctions RPC et extensions PostgreSQL

Lorsque vous exposez des fonctions stockées (CREATE FUNCTION) appelables depuis le client via supabase.rpc() :

  • Privilégier SECURITY INVOKER : Par défaut, concevez vos fonctions en SECURITY INVOKER afin qu'elles s'exécutent avec les permissions et le contexte RLS de l'utilisateur qui effectue l'appel.
  • Sécuriser SECURITY DEFINER lorsque c'est indispensable : Si une fonction doit nécessairement s'exécuter avec les privilèges de son créateur (par exemple pour insérer dans une table d'audit non accessible à l'utilisateur), fixez explicitement un search_path sûr — idéalement vide (SET search_path = '') selon la recommandation officielle Supabase — et préfixez systématiquement tous les noms de tables et de types par leur schéma (public.documents). Validez également rigoureusement l'identité de l'appelant (auth.uid()) au sein de la fonction.
  • Permissions d'exécution : Révoquez l'accès public par défaut (REVOKE EXECUTE ON FUNCTION ... FROM public;) et accordez-le uniquement aux rôles nécessaires (GRANT EXECUTE ON FUNCTION ... TO authenticated;).

6. Vérifier les opérations destructives (UPDATE / DELETE)

Une erreur fréquente dans les applications d'édition consiste à vérifier l'authentification sans vérifier la propriété de la ligne modifiée :

  • Assurez-vous que chaque mutation exige une clause d'appartenance. Par exemple, une mise à jour d'un document doit vérifier que auth.uid() = user_id.
  • Empêchez l'élévation de privilèges : si votre table de profils contient un champ role, assurez-vous via un trigger ou une politique stricte qu'un utilisateur ne peut pas s'auto-attribuer le statut administrateur via une requête API directe.

7. Assainir les journaux et cibler les colonnes récupérées

Vérifiez les données retournées par vos requêtes et vos journaux d'application :

  • Éviter SELECT * sur les requêtes sensibles : Privilégiez la sélection explicite des seules colonnes nécessaires à l'écran. Évitez SELECT * lorsque cela risque de rapatrier ou d'exposer inutilement des champs privés, techniques ou des colonnes sensibles dans le payload JSON transmis au client.
  • Logs serveur : Assurez-vous que vos Route Handlers ou Server Actions n'enregistrent pas les jetons de session, les mots de passe ou les emails en clair dans les outils de suivi externe.

8. Tester avec plusieurs profils étanches

Avant de déclarer votre projet prêt pour la production, réalisez systématiquement le test des trois profils :

  1. Profil Non Connecté (Visiteur anonyme) : Tentez d'accéder aux endpoints et aux tables. Seules les données explicitement publiques doivent être lisibles.
  2. Profil Utilisateur A : Créez une ressource privée et notez son identifiant (UUID).
  3. Profil Utilisateur B : Dans une session de navigation privée distincte, tentez d'accéder directement à la ressource de l'utilisateur A en lecture, en modification et en suppression. La réponse doit être vide ou bloquée avec une erreur 404/403.

9. Checklist récapitulative avant mise en ligne

Utilisez cette liste de contrôle rapide pour valider chaque table avant le déploiement :

□ RLS est activé sur 100 % des tables du schéma public
□ Aucune table privée ne dispose d'une règle "FOR ALL USING (true)"
□ Les opérations INSERT valident "WITH CHECK (auth.uid() = user_id)"
□ La clé "service_role" est absente du code client et des variables NEXT_PUBLIC_
□ Les URLs de redirection Supabase Auth sont restreintes à votre domaine
□ Les fonctions sont en SECURITY INVOKER, ou SECURITY DEFINER avec search_path fixé
□ Le test croisé entre deux comptes utilisateurs distincts a été validé avec succès

Vérification continue avec GVO

Pour auditer votre application de façon automatique et reproductible, vous pouvez connecter votre référentiel de code à GVO :

  • Ce que GVO analyse : GVO examine vos composants, vos Server Actions et vos schémas de base de données pour détecter l'absence démontrable de protection RLS, les politiques visiblement trop permissives, les fuites de secrets vers le navigateur et les risques de surcoûts d'API.
  • Résultats et preuves : Chaque observation est classée avec précision (Confirmé, Probable, À vérifier) et accompagnée des extraits de code source concernés, sans jamais prétendre à une certification magique de conformité.

Pour comprendre la signification des constats générés lors d'un audit de votre projet, reportez-vous à la documentation sur la Compréhension d'un finding GVO.

Vérifier ce point sur votre projet

GVO confronte le code et les configurations de votre application aux règles de sécurité réelles.