Row Level Security uitgelegd: waarom je app klantdata lekt
Het lek dat we het vaakst tegenkomen bij snel gebouwde applicaties is telkens hetzelfde: de database staat open. Niet omdat iemand een fout maakte in de code, maar omdat er nooit een regel is ingesteld die zegt wie wat mag zien. In Postgres, en dus in Supabase, heet dat mechanisme Row Level Security.
Dit stuk legt uit wat RLS is, waarom het bij een applicatie met een clouddatabase geen optie maar een noodzaak is, en hoe je in vijf minuten controleert of het bij jou goed staat.
Het probleem in één alinea
Bij een klassieke opzet praat je browser met een server, en die server praat met de database. De server bepaalt wat je te zien krijgt. Bij moderne clouddatabases praat je browser rechtstreeks met de database. Dat is sneller en scheelt werk, maar het betekent ook dat de laag die vroeger bepaalde wat jij mocht zien, er niet meer is. Die verantwoordelijkheid verhuist naar de database zelf.
Doe je daar niets mee, dan geldt: wie de sleutel van je frontend heeft (en die heeft iedere bezoeker, want hij staat in de broncode) kan alles opvragen. Niet alleen zijn eigen rijen. Alle rijen.
Wat Row Level Security doet
RLS verplaatst de vraag "mag deze gebruiker deze rij zien?" naar de database. Je zet het aan per tabel, en daarna geldt: alles is verboden, tenzij een policy het toestaat. Die omkering is precies wat je wil, want vergeten betekent dan dicht in plaats van open.
-- Zonder deze regel is elke policy hieronder zinloos.
alter table bestellingen enable row level security;Let op de valkuil: het aanmaken van policies terwijl RLS uitstaat geeft geen foutmelding. Je ziet een keurige lijst met regels in je dashboard en denkt dat het geregeld is, terwijl er niets wordt afgedwongen.
Een policy schrijven
Een policy beschrijft welke rijen zichtbaar zijn voor wie. De meest voorkomende vorm: een gebruiker mag alleen zijn eigen rijen zien. In Supabase geeft de functie auth.uid() het id van de ingelogde gebruiker.
create policy "eigen bestellingen lezen"
on bestellingen
for select
using (auth.uid() = gebruiker_id);Belangrijk: dit dekt alleen lezen. Toevoegen, wijzigen en verwijderen zijn aparte operaties met aparte policies. Een applicatie waarin lezen dichtgetimmerd is maar iedereen mag schrijven, komt vaker voor dan je zou hopen.
create policy "eigen bestellingen toevoegen"
on bestellingen
for insert
with check (auth.uid() = gebruiker_id);
create policy "eigen bestellingen wijzigen"
on bestellingen
for update
using (auth.uid() = gebruiker_id)
with check (auth.uid() = gebruiker_id);Het verschil tussen using en with check
Dit onderscheid kost mensen de meeste tijd, dus kort: using wordt toegepast op rijen zoals ze nú zijn, with check op rijen zoals ze ná de bewerking zouden zijn. Bij een update heb je allebei nodig. Laat je with check weg, dan mag een gebruiker zijn eigen rij pakken en er andermans gebruiker_id in zetten. Daarmee geeft hij hem weg, of erger: hij neemt hem over.
De drie fouten die we het vaakst zien
- RLS staat uit terwijl er wel policies zijn. Alles ligt open, en het dashboard oogt geruststellend.
- Een policy met using (true). Dat betekent letterlijk "iedereen mag alles" en wordt vaak tijdens het bouwen ingezet om verder te kunnen, en dan vergeten.
- Alleen een select-policy. Lezen is dicht, maar insert, update en delete staan open omdat daar niets voor is ingesteld.
Alle drie zijn ze te vinden zonder één regel code te schrijven, en dat is precies wat de volgende paragraaf doet.
Zelf controleren in vijf minuten
Draai deze query in de SQL-editor van je database. Hij laat per tabel zien of RLS aanstaat en hoeveel policies er zijn.
select
c.relname as tabel,
c.relrowsecurity as rls_aan,
count(p.polname) as aantal_policies
from pg_class c
join pg_namespace n on n.oid = c.relnamespace
left join pg_policy p on p.polrelid = c.oid
where n.nspname = 'public' and c.relkind = 'r'
group by c.relname, c.relrowsecurity
order by c.relrowsecurity, c.relname;Staat er ergens false, dan is die tabel volledig leesbaar voor iedereen met je publieke sleutel. Staat rls_aan op true maar is het aantal policies nul, dan is het tegenovergestelde waar: niemand komt erbij, ook je eigen applicatie niet. Dat is minder erg, maar het verklaart waarom er soms opeens niets meer werkt.
Waar je nog meer op moet letten
RLS goed instellen is de basis, niet het hele verhaal. Twee dingen die er direct naast horen.
Ten eerste: de service-sleutel. Elke clouddatabase heeft een sleutel die álle policies negeert, bedoeld voor serverwerk. Die hoort nooit in je frontend, in je repository of in een omgevingsvariabele die naar de browser wordt gestuurd. Staat hij daar wel, dan maakt het niet uit hoe goed je policies zijn.
Ten tweede: views. Een view op een tabel met RLS erft die beveiliging niet automatisch zoals je zou verwachten. Bouw je views over gevoelige tabellen, controleer dan expliciet wie daar doorheen kan kijken.
En tenslotte: test het als aanvaller, niet als eigenaar. Log uit, of log in als een tweede testgebruiker, en probeer de gegevens van de eerste op te halen. Krijg je ze te zien, dan weet je genoeg. Dat is een test van vijf minuten die je in je hoofd nooit goed doet. Bij een webapplicatie die wij bouwen staan die policies er vanaf de eerste versie in.
Veelgestelde vragen
Wat is Row Level Security precies?
Heb ik RLS nodig als mijn app geen inlog heeft?
Is de publieke sleutel van Supabase geheim?
Vertragen policies mijn applicatie?
Lees ook
Wat hierop aansluit. Geschreven voor ondernemers, niet voor collega’s.
- Je AI-website: 7 dingen die misgaanEen AI-tool bouwt wat je vraagt en waarschuwt niet voor wat je vergat te vragen. De zeven problemen die wij het vaakst tegenkomen, van een database die openstaat tot een contactformulier dat nergens heen stuurt.
- Waarom kiezen voor een maatwerk webapplicatie?Standaardsoftware dwingt je bedrijf in een mal; een maatwerk webapplicatie vormt zich naar jouw processen. Wanneer die investering loont, en wanneer juist niet.
- Zelf bouwen met AI-toolsKun je je website zelf bouwen met AI? Vaak wel, en het hangt sterk af van wat je maakt. Een eerlijke afweging per soort project, van ontwerptools als Google Stitch tot bouwers als Lovable.



