De autorisatie die een scanner niet ziet
Broken access control is de meest misbruikte webkwetsbaarheid die er is, en onzichtbaar voor een tool met maar één login. De test is het ene account dat de gegevens van het andere probeert te bereiken.
De meest voorkomende serieuze fout in webapplicaties op dit moment is geen exotische injectie. Het is een pagina die gegevens laadt die hij had moeten weigeren. Broken access control staat bovenaan de risicolijsten omdat het overal zit, en omdat de gebruikelijke tools er recht langs lopen.
De reden dat ze er langs lopen is simpel. Een scanner logt één keer in, als één gebruiker, en controleert of de pagina's die die gebruiker mag zien antwoorden. Dat doen ze. Er lijkt niets mis. De fout verschijnt pas wanneer een tweede gebruiker om de gegevens van de eerste vraagt, en een tool met één account stelt die vraag nooit.
Een object per keer
Neem een bestelpagina. Ingelogd als jezelf open je je eigen factuur.
GET /api/orders/1001 (session: alice) -> 200 { total, address, items }
GET /api/orders/1002 (session: alice) -> 200 { total, address, items }Het eerste request is prima. Het tweede is de finding. Bestelling 1002 hoort bij een andere klant, en de server gaf hem vrij omdat hij controleerde dat Alice was ingelogd maar nooit dat de bestelling van haar was. Dat is een insecure direct object reference, en het leest bankafschriften, downloadt andermans documenten en wijzigt records die nooit van jou waren, één identifier per keer.
Hetzelfde gat zit één niveau hoger. Een veld op een gedeeld type dat alleen een beheerder zou mogen schrijven. Een endpoint dat een rol vertrouwt die de client meestuurt. Een tenant-grens die standhoudt in het lijstoverzicht en lekt in de detailweergave. Elk is dezelfde fout: de code bevestigde wie je bent en vergat te bevestigen wat je mag aanraken.
Hoe we het testen
We testen met twee accounts, met opzet. Alles wat het ene account kan bereiken vragen we opnieuw op vanuit het andere, waarbij we alleen de identifier veranderen. We lopen de objectverwijzingen af die de applicatie uitdeelt en proberen elke vanuit een positie die geweigerd zou moeten worden. We sturen de rollen en vlaggen die een client niet hoort te zetten en kijken of de server ze gelooft.
Daarna wordt elke treffer met de hand gereproduceerd, want autorisatie is precies waar een geautomatiseerde gok de mist in gaat. Een 200 kan een lege template zijn. Een 403 kan een neveneffect verbergen dat toch plaatsvond. We bevestigen dat er echte gegevens over een grens gingen voordat we het een finding noemen, en we voegen de twee requests toe die het bewijzen.
Authenticatie vraagt wie je bent. Autorisatie vraagt wat van jou is. De meeste tools testen alleen het eerste.
Access control laat zich niet veilig scannen, want de vraag gaat over je datamodel, niet over je responscodes. Het moet gelopen worden, account tegen account, object tegen object. Dat is traag, het automatiseert niet netjes, en het is waarom we het met de hand doen en waarom het vindt wat de scan miste.