Waarom apps die met AI zijn gebouwd vaak dezelfde zwakke plekken hebben
Tools als Lovable, Bolt, v0, Replit, Cursor en Claude zijn goed in wat je ziet: schermen, knoppen, formulieren en een database erachter. Beveiliging zie je niet. Een app waarin iedere gebruiker de gegevens van alle andere gebruikers kan opvragen, ziet er precies hetzelfde uit als een app waarin dat niet kan. Zolang niemand het probeert, merk je het verschil niet.
Daarbij bouwt een AI-tool wat je vraagt. Vraag je om een klantenoverzicht, dan krijg je een klantenoverzicht. Of dat overzicht alleen voor de juiste mensen zichtbaar is, hangt af van regels die je er zelf om moet vragen, en die de AI soms weer weghaalt als iets niet meteen werkt.
Dat dit geen theorie is, liet 2025 zien. Voor apps die met Lovable waren gemaakt, werd een kwetsbaarheid geregistreerd (CVE-2025-48757): door te ruime databaseregels konden buitenstaanders gegevens lezen of aanpassen zonder in te loggen. Lovable betwist die registratie, met als argument dat iedere klant zelf verantwoordelijk is voor de beveiliging van de gegevens in zijn app. En daar zit precies de kern: die verantwoordelijkheid ligt bij jou, ook als een AI de code schreef.
Het goede nieuws: de fouten lijken op elkaar. Wie weet waar hij moet kijken, vindt de meeste in een paar uur. Hieronder staan de tien punten die ik bij elke app als eerste nakijk.
De 10 punten om te controleren
Loop de lijst van boven naar beneden door. De eerste drie punten zijn het belangrijkst: daar zitten de lekken waarmee iemand in één keer al je gegevens kan meenemen.
- 1Geheime sleutels: staan er sleutels van bijvoorbeeld Stripe, OpenAI of de service_role-sleutel van Supabase in code die in de browser draait? Dan kan iedereen ze vinden en gebruiken.
- 2Databaseregels: staat Row Level Security in Supabase aan voor elke tabel, of zijn je Firebase Security Rules strenger dan ‘iedereen mag alles’? Zonder die regels is je database vanuit de browser open.
- 3Rechten per gebruiker: ziet een ingelogde gebruiker alleen zijn eigen gegevens? Test het met twee accounts en kijk wat er gebeurt als je in de adresbalk het nummer van een klant of bestelling verandert.
- 4Beheerpagina’s: zijn pagina’s voor beheerders alleen uit het menu weggehaald, of controleert de server echt of iemand beheerder is?
- 5Invoer: controleert je app wat gebruikers invullen, ook aan de serverkant? Ongecontroleerde invoer opent de deur naar injectie, waarbij iemand eigen code of databasecommando’s laat uitvoeren.
- 6Pakketten en updates: draait je app op pakketten met bekende kwetsbaarheden (CVE’s)? Hoe ouder de pakketten, hoe groter de kans.
- 7Bestanden en opslag: wie kan geüploade bestanden bekijken? Een opslagmap die op openbaar staat, is leesbaar voor iedereen die de link heeft of raadt.
- 8Misbruik: kan iemand duizend keer per minuut proberen in te loggen, of je AI-functie laten draaien op jouw rekening? Zonder limieten betaal jij de rekening van misbruik.
- 9Foutmeldingen: laat je app bij een fout technische details zien, zoals databasenamen of stukken code? Die informatie helpt een aanvaller verder.
- 10Back-ups, logs en monitoring: kun je je data terugzetten als het misgaat, en merk je een storing of inbraak zelf op voordat je klanten het je vertellen?
Sleutels en databaseregels: begin hier
Een app die met Supabase werkt, gebruikt twee soorten sleutels. De publieke sleutel (de anon key, in nieuwere projecten de publishable key) hoort in de browser en mag gezien worden. De geheime sleutel (service_role, of secret key) omzeilt alle databaseregels en hoort alleen op een server. Volgens de documentatie van Supabase mag die sleutel nooit in de browser terechtkomen, of op een andere plek waar gebruikers hem kunnen zien.
Die publieke sleutel is alleen veilig als de database zelf bepaalt wie welke rijen mag lezen en wijzigen. In Supabase heet dat Row Level Security, kortweg RLS. Staat RLS uit, dan kan iedereen met de publieke sleutel, die dus in je website staat, hele tabellen opvragen. Bij Firebase speelt hetzelfde met de Security Rules: een regel die lezen en schrijven voor iedereen toestaat, is tijdens het bouwen handig en na de lancering een open deur.
Zelf controleren kan zo: open je app in de browser, open de ontwikkelaarstools en zoek in de geladen JavaScript naar woorden als service_role, sk_live of sk-. Vind je een geheime sleutel, trek hem dan in bij de aanbieder en maak een nieuwe aan. Alleen weghalen uit de code is niet genoeg, want de oude sleutel kan al gekopieerd zijn. Kijk daarna in het dashboard van Supabase of Firebase welke tabellen geen regels hebben.
Let ook op instellingen met een voorvoegsel als VITE_ of NEXT_PUBLIC_. Die worden bewust in de code voor de browser gezet. Een geheime sleutel met zo’n naam is dus voor iedereen zichtbaar, hoe netjes hij ook in een configuratiebestand staat.
Inloggen is nog geen toegangscontrole
Veel founders denken: mijn app heeft een inlogscherm, dus hij is beveiligd. Maar inloggen bewijst alleen wie iemand is. De vraag wat die persoon mag zien en doen, is een tweede stap, en die vergeten AI-tools nog weleens. Het is ook geen klein probleem: in de OWASP Top 10 van 2025, de bekendste lijst van beveiligingsrisico’s voor webapps, staat gebrekkige toegangscontrole op de eerste plaats.
Een veelvoorkomend voorbeeld: je factuuroverzicht staat op een adres dat eindigt op /facturen/1042. Een klant verandert dat nummer in 1041 en ziet de factuur van iemand anders. De app controleert wel dat de klant is ingelogd, maar niet of de factuur van hem is.
Testen kost je een kwartier. Maak twee testaccounts aan, log met het ene account in en kopieer de adressen van een paar pagina’s met eigen gegevens. Log in met het tweede account en open die adressen. Krijg je de gegevens van het eerste account te zien, dan heb je een lek. Doe hetzelfde met beheerpagina’s: open ze als gewone gebruiker en als je niet bent ingelogd.
Pakketten en updates: het werk na de lancering
Je app bestaat maar voor een klein deel uit code die voor jou is geschreven. De rest bestaat uit honderden pakketten van anderen: voor inloggen, betalingen, datums en ga zo maar door. In die pakketten worden steeds nieuwe kwetsbaarheden gevonden. Zodra er een bekend is, krijgt hij een CVE-nummer en staat hij in openbare databases. Ook voor aanvallers, die geautomatiseerd zoeken naar sites die nog een oude versie draaien.
Niet voor niets is ‘Software Supply Chain Failures’ nieuw in de OWASP Top 10 van 2025: problemen in de pakketten en hulpmiddelen waarmee je app wordt gebouwd. Een app die bij de lancering veilig was, is dat een half jaar later niet meer vanzelf.
Wat helpt: laat een tool als npm audit, Dependabot of Renovate je pakketten automatisch controleren, en werk kritieke updates snel bij. Test na elke update of je app nog werkt, want een update die iets breekt, is precies de reden dat mensen updates uitstellen. Bij mijn onderhoudsplannen controleer ik daarom dagelijks op bekende kwetsbaarheden en werk ik de pakketten bij, zodat jij daar niet aan hoeft te denken.
Als het toch misgaat: back-ups, logs en monitoring
Geen app is honderd procent veilig. Daarom is de vraag niet alleen hoe je een probleem voorkomt, maar ook hoe snel je het merkt en hoe je weer terugkomt. Drie dingen maken daar het verschil.
Back-ups: maak automatische back-ups van je database en bewaar ze ergens anders dan je app. Een back-up die je nooit hebt teruggezet, is een hoop, geen plan. Probeer het dus minstens één keer. Logs: leg vast wie wanneer inlogt en wat er misgaat, zonder wachtwoorden of andere gevoelige gegevens in die logs te zetten. Zonder logs kun je achteraf niet zien wat er is gebeurd. Monitoring: laat een dienst je app elke paar minuten controleren en je waarschuwen als hij onbereikbaar is of ineens veel fouten geeft.
Let ook op wat je app bij een fout laat zien. Een gebruiker heeft niets aan een melding vol technische details, maar een aanvaller wel. Toon een nette melding aan de gebruiker en zet de details in je logs.
Persoonsgegevens en de AVG
Verwerkt je app namen, e-mailadressen of andere persoonsgegevens, dan geldt de AVG, de Europese privacywet. Dit is geen juridisch advies, maar een paar basisvragen horen bij elke beveiligingscontrole. Verzamel je alleen wat je echt nodig hebt? Weet je in welk land je database staat? En heb je met de diensten die gegevens voor je opslaan, zoals je hosting en je database, een verwerkersovereenkomst?
Gaat het mis en lekken er persoonsgegevens, dan moet je dat in veel gevallen binnen 72 uur melden bij de Autoriteit Persoonsgegevens. Dat lukt alleen als je het zelf op tijd merkt, en als je kunt nagaan welke gegevens zijn gelekt. Ook daarom zijn logs en monitoring geen luxe.
Zelf controleren of laten controleren?
De tests met twee accounts, het zoeken naar sleutels in de browser en het nalopen van je databaseregels kun je prima zelf doen. Wat lastiger is: beoordelen of de regels die er staan ook kloppen, of de server echt controleert wat de schermen beloven en welke pakketten een probleem vormen. Daarvoor moet je de code kunnen lezen.
Daarvoor is mijn App Check. Voor €600 (excl. btw) controleer ik één app van maximaal 15 schermen, met één database en maximaal 3 koppelingen, zoals betalingen, e-mail of inloggen met Google. Binnen 5 werkdagen krijg je een rapport in gewone taal, met de risico’s op volgorde van rood, oranje en groen, en lopen we het in 30 minuten samen door. Start je daarna binnen 30 dagen een onderhoudsplan, dan verreken ik de €600 volledig.
Voor de duidelijkheid: een App Check is geen formele penetratietest. Heb je die nodig, bijvoorbeeld voor een certificering of omdat een grote klant erom vraagt, dan is een gespecialiseerd bureau de juiste partij. Na een App Check ga je daar wel beter voorbereid naartoe.
Veelgestelde vragen
- Mijn app werkt goed. Waarom zou hij onveilig zijn?
- Omdat werken en veilig zijn twee verschillende dingen zijn. Een app kan alle schermen goed tonen en tegelijk iedereen toestaan om via de database alle gegevens op te vragen. Dat zie je pas als je het test, bijvoorbeeld met twee accounts.
- Is het een probleem dat de sleutel van Supabase in mijn website staat?
- De publieke sleutel (anon of publishable key) is bedoeld voor de browser en mag zichtbaar zijn, op voorwaarde dat Row Level Security aanstaat voor elke tabel. De geheime sleutel (service_role of secret key) mag nooit in de browser staan.
- Is een App Check hetzelfde als een pentest?
- Nee. Bij een App Check controleer ik de code, de instellingen en de pakketten van je app op de bekende zwakke plekken, en krijg je een rapport in gewone taal. Een formele penetratietest door een gespecialiseerd bureau is een andere dienst, die ik niet aanbied.
- Hoe vaak moet ik mijn app controleren?
- Doe een volledige controle voor je lancering en na elke grote wijziging. Pakketten en updates verdienen doorlopend aandacht, omdat er steeds nieuwe kwetsbaarheden bekend worden. Daarom zit een dagelijkse controle daarop in mijn onderhoudsplannen.
Laat je app controleren voordat iemand anders het doet
Met de App Check weet je binnen 5 werkdagen hoe veilig je app is, met een rapport in gewone taal en een vaste prijs van €600. Neem je daarna een onderhoudsplan, dan verreken ik dat bedrag volledig.