Uit de praktijk
Je app werkt, maar is hij ook dicht? Drie lekken uit onze eigen security review
Met AI bouw je in weken wat vroeger maanden kostte. Bij een eigen security review vonden we drie lekken in een app die gewoon werkte. Wat het waren, hoe we ze dichtten en welke checks je zelf kunt doen.
Door Daniël van der Krans 7 min lezen
Snel bouwen is ons vak. Met AI-assistenten bouwen we in weken wat een paar jaar geleden maanden kostte. Maar “het werkt” en “het is veilig” zijn twee verschillende tests. De eerste doet elke gebruiker vanzelf. De tweede doet niemand, tenzij je hem plant.
Vorige week planden we hem. We lichtten een van de webapps door die we bouwen en beheren, een app waarin meerdere organisaties met eigen accounts werken. Geen incident, geen melding van buiten. Een geplande review, met een AI-assistent als tweede paar ogen.
We vonden drie lekken. Alle drie zaten op plekken waar de app voor normale gebruikers precies deed wat hij moest doen. Daarom delen we ze.
Lek 1: de resetlink die je zelf kon richten
Wachtwoord vergeten? Je vult je e-mailadres in en krijgt een mail met een link. Het webadres in die link werd opgebouwd uit een waarde die in het verzoek zelf meekwam. Normaal is dat gewoon het adres van de app. Maar wie dat verzoek zelf opstelde, kon er een ander adres in zetten.
Het gevolg: een echte mail, verstuurd door de app, naar de echte gebruiker, met een link naar een domein van iemand anders. De resetcode in die link kwam daar terecht. Sommige mailscanners openen links al voordat de ontvanger de mail leest, dus klikken was niet eens nodig. Zo kon iemand een account overnemen, ook dat van een beheerder.
De oplossing: de app accepteert alleen nog adressen van een vaste lijst, met een exacte vergelijking. Een afgewezen verzoek krijgt een gewoon antwoord zonder mail, zodat niemand kan aflezen wat er gecontroleerd wordt, en er komt een regel in het log.
Lek 2: gearchiveerd, maar nog binnen
Wie een gebruiker archiveerde, zag die gebruiker uit de schermen verdwijnen. Maar de controle bij het inloggen keek niet naar dat archief-vinkje, en lopende sessies bleven geldig. Een gearchiveerde beheerder kon dus gewoon doorwerken zolang een oude sessie openstond.
De oplossing: de controle bij elke login weigert gearchiveerde gebruikers. Archiveren verwijdert in dezelfde stap alle sessies. En je kunt niet meer jezelf of de laatste beheerder archiveren.
Bij het uitzoeken vonden we nog iets. De functie die een gebruiker geforceerd moest uitloggen, heeft nooit gewerkt. Hij kreeg het verkeerde soort gegevens mee. In de logs stond er een waarschuwing over, maar die werd gezien als ruis. Een waarschuwing die je wegklikt, is een fout die je nog niet hebt gevonden.
Lek 3: de doorstuurlink na het inloggen
Na het inloggen stuurt de app je terug naar de pagina waar je vandaan kwam. Dat adres staat in de link. Met een slim opgebouwde waarde stuurde de browser je door naar een heel andere site.
Op zichzelf een klein risico. Maar het is precies wat iemand nodig heeft voor een overtuigende phishingmail: een link die echt op jouw domein begint. De oplossing: één centrale functie die elke doorverwijzing controleert op het eigen domein en toegestane paden.
In dezelfde ronde maakten we de mailsjablonen strenger. Webadressen die in een mail worden ingevoegd, moeten nu met http of https beginnen en worden netjes gecodeerd.
Dichtzetten zonder iets te breken
Een lek dichten is één ding. Het dichten zonder dat de rest van de app omvalt, is het echte werk. We hielden ons aan een vaste volgorde:
- Kleinste risico eerst. Fixes zonder databasewijziging gingen los en snel live.
- Riskantste wijziging apart. De controle die bij elke login draait, kreeg een eigen wijziging, getest met nagebootste logins en met een terugdraaiscript klaar.
- Een mens test in de browser voordat het live gaat. Daarna controleren we op productie, alleen lezend, of alles werkt zoals bedoeld.
Vijf checks voor elke app die snel gebouwd is
- Bouw nooit een link of doorverwijzing uit iets wat de gebruiker meestuurt. Gebruik een vaste lijst en een exacte vergelijking.
- Toegang intrekken is sessies intrekken. Test het: archiveer een gebruiker die op een ander apparaat nog ingelogd is.
- Controleer rechten in de database zelf. Wat het scherm verbergt, is daarmee nog niet afgeschermd.
- Kijk naar de draaiende omgeving, niet alleen naar de code. Rechten en instellingen op productie kunnen afwijken van wat je denkt dat er staat.
- Plan de review. Elke wijziging aan inloggen of rechten krijgt een tweede paar ogen. Een AI-assistent is een goede eerste reviewer, een mens beslist.
Wat dit zegt over bouwen met AI
Dit is geen pleidooi tegen bouwen met AI. Dezelfde AI hielp ons deze lekken in uren te vinden in plaats van dagen. Het punt is dat snelheid in het bouwen vraagt om discipline in het controleren.
Draait er in jouw organisatie een app die snel is gebouwd, door een bureau, een collega of jezelf met een AI-assistent? Stel dan drie vragen. Wanneer is hij voor het laatst doorgelicht, door wie, en wat is er gecontroleerd? Als niemand dat weet, is dat de eerste stap.