ADR-0003 - RLS permissive, contrôle d'accès côté client
- Statut : 🔴 Accepté (état de fait) - À REMPLACER en priorité (P0)
- Date : 2026-07-10 (constat)
- Tags : sécurité, RGPD, base de données
Contexte
Supabase applique la Row Level Security (RLS) de PostgreSQL pour décider qui peut lire/écrire quoi. Dans ce projet, toutes les tables ont la même policy :
CREATE POLICY "Authenticated full access" ON <table>
FOR ALL USING (auth.role() = 'authenticated')
WITH CHECK (auth.role() = 'authenticated');
(Voir supabase-schema.sql:90-94, supabase-payroll.sql:34, supabase-planning.sql:32-33.)
Le commentaire du schéma l'assume : « le contrôle admin/manager se fait côté app ».
Les rôles (admin/manager/employee) et les périmètres (scope_type/scope_id)
ne sont donc vérifiés que dans le JavaScript (isAdmin, visibleEmployees, NAV…).
Décision (constatée)
Autoriser tout utilisateur authentifié à faire SELECT/INSERT/UPDATE/DELETE
sur toutes les tables, et gérer la visibilité/les droits uniquement dans l'UI.
Conséquences
Positives
- Développement simple : aucune policy fine à écrire.
Négatives / RISQUE MAJEUR
- La clé
anonest publique (présente dans le bundle JS). N'importe quel utilisateur connecté - y compris un simple salarié ou un manager - peut, en dehors de l'interface (console navigateur,curl, client Supabase), exécuter par ex.supabase.from('employees').select('*')et récupérer les salaires, RIB, adresses, dates de naissance de tout le monde, ou modifier/supprimer des lignes. - Non-conformité RGPD : pas de minimisation ni de cloisonnement d'accès aux données personnelles.
- Le badge « rôle » et le filtrage
visibleEmployeesdonnent une fausse impression de cloisonnement.
Alternatives / Remédiation cible (proposée - à acter en ADR séparé)
| Option | Description | Reco |
|---|---|---|
| Policies RLS par rôle | Lire app_users.role/scope_* dans les policies (fonctions auth.uid() → rôle) |
✅ Recommandé |
| Vue « employé » restreinte | Un salarié ne voit que sa ligne ; un manager que son périmètre | ✅ |
| Colonnes sensibles séparées | Isoler salaire/RIB dans une table à accès admin | ✅ (complément) |
| Edge Function de confiance | Exposer des RPC contrôlées plutôt que l'accès table brut | ⏳ option |
Esquisse de policy cible (employés) :
-- Un admin voit tout ; un salarié voit sa fiche ; un manager voit son périmètre.
CREATE POLICY employees_select ON employees FOR SELECT USING (
is_admin(auth.uid())
OR employee_self(auth.uid(), employees.id)
OR employee_in_manager_scope(auth.uid(), employees.id)
);
Détails et prompt d'implémentation : ../prompts/05-durcir-securite-rls.md.
Références
gestionrh-github/supabase-schema.sql:78-94gestionrh-github/src/App.jsx:isAdmin,visibleEmployees,MANAGER_PAGES
