Gids API-beveiliging voor schaalbare webapps

Een klant wijzigt één getal in een API-request en ziet opeens de bestelling, factuur of bedrijfsgegevens van een andere klant. Dit is geen theoretisch securityprobleem. Het is een omzet-, reputatie- en continuïteitsrisico dat ontstaat wanneer autorisatie alleen op de frontend wordt gecontroleerd. Deze gids API-beveiliging voor webapps laat zien waar bedrijven de controle verliezen en hoe u die terugbouwt in de architectuur.
Een moderne webapp hangt zelden aan één systeem. De webshop praat met een PIM, ERP, PSP, CRM, voorraadplatform, verzendpartij en soms met interne tooling. Iedere koppeling vergroot de operationele slagkracht, maar ook het aanvalsoppervlak. Wie API-beveiliging behandelt als een laatste test voor livegang, bouwt technische schuld in een bedrijfskritisch kanaal.
API-beveiliging voor webapps begint bij bedrijfsrisico
Een API is de verkeerslaag tussen gebruikers, applicaties en systemen. Daar gaan klantdata, prijzen, voorraadmutaties, orderregels, rollen en vaak betaalstatussen doorheen. Een fout in die laag is daarom zelden beperkt tot een technisch incident. Denk aan een groothandelsklant die aangepaste contractprijzen van een concurrent kan ophalen, een frauduleuze gebruiker die coupons automatiseert of een bot die de checkout zo zwaar belast dat betalende bezoekers afhaken.
De juiste vraag is niet: is onze API beveiligd? De juiste vraag is: welke acties, gegevens en integraties mogen onder geen beding door de verkeerde partij worden benaderd, gewijzigd of vertraagd?
Dat onderscheid dwingt prioriteit af. Niet elke endpoint heeft hetzelfde risicoprofiel. Een publieke productfeed vraagt om andere maatregelen dan een endpoint voor facturen, retourautorisaties of beheerdersrechten. Door processen aan endpoints te koppelen, wordt security een onderdeel van risicobeheersing in plaats van een technische checklist.
Authenticatie is niet hetzelfde als autorisatie
De meest kostbare fouten zitten vaak in het verschil tussen authenticatie en autorisatie. Authenticatie beantwoordt de vraag wie iemand is. Autorisatie bepaalt wat die persoon binnen een specifieke context mag doen.
Een geldige login of access token bewijst dus niet dat een gebruiker order 48291 mag uitlezen, een prijsregel mag aanpassen of een medewerker mag uitnodigen. De backend moet dit bij iedere gevoelige aanvraag vaststellen. Niet de React-interface, niet een verborgen knop en niet een parameter die de browser zelf meestuurt.
Bescherm tegen BOLA en IDOR
BOLA, ook bekend als IDOR, ontstaat wanneer een applicatie controleert of iemand is ingelogd, maar niet controleert of het opgevraagde object ook van die gebruiker of organisatie is. Dit gebeurt bijvoorbeeld bij requests als `/orders/48291` of `/customers/981`.
De oplossing is eenvoudig in principe, maar vraagt discipline in de codebase: koppel objecttoegang altijd aan de identiteit en tenant van de ingelogde gebruiker. Haal een order niet op op basis van alleen een order-ID. Query op order-ID én organisatie-ID of klant-ID uit de gevalideerde sessie. Gebruik daarbij waar mogelijk niet-opeenvolgende publieke identifiers. Dat voorkomt geen autorisatiefout, maar maakt massaal raden minder triviaal.
In B2B-portalen wordt dit complexer door meerdere rollen binnen één organisatie. Een inkoper mag wellicht bestellen, een finance-rol mag facturen zien en een accountmanager mag gebruikers beheren. Leg deze rechten centraal vast. Verspreide if-statements door controllers en frontendcomponenten zijn op termijn niet te auditen en vrijwel onmogelijk consistent te onderhouden.
Kies tokens die bij uw architectuur passen
Voor browsergebaseerde webapps zijn sessiecookies en tokengebaseerde authenticatie beide verdedigbare keuzes. De beste keuze hangt af van uw platform, domeinstructuur, mobiele apps, externe clients en vereiste sessieduur. Er bestaat geen universele winnaar.
Cookies met de flags `HttpOnly`, `Secure` en een passende `SameSite`-instelling beperken het risico dat JavaScript sessiegegevens uitleest. Daartegenover staat dat u CSRF-bescherming goed moet ontwerpen, zeker wanneer uw frontend en API op verschillende domeinen draaien. Tokens kunnen prettig werken voor mobiele apps en machine-to-machine-integraties, maar tokens in local storage maken XSS-schade potentieel groter.
Wat niet onderhandelbaar is: tokens moeten kort leven, rotatie moet mogelijk zijn en intrekking moet werken bij verdachte activiteit, wachtwoordwijzigingen of vertrek van medewerkers. Een token dat maanden geldig blijft, verandert een eenmalig lek in langdurige toegang.
API-keys verdienen aparte aandacht. Gebruik nooit één permanente sleutel voor alle omgevingen, klanten of integraties. Geef elke integratie een eigen key, beperk de rechten per key en roteer sleutels aantoonbaar. Een sleutel voor orderstatussen hoeft geen klantprofielen te lezen of prijzen te wijzigen.
Valideer iedere request aan de serverkant
Een API moet input behandelen als onbetrouwbaar, ook wanneer die uit uw eigen frontend komt. Browsers kunnen worden gemanipuleerd, requests kunnen direct worden herhaald en integraties sturen niet altijd wat u verwacht.
Valideer daarom type, lengte, formaat, bereik en toegestane waarden voor alle invoer. Gebruik een expliciet schema per endpoint. Verwacht u een aantal tussen 1 en 100? Accepteer dan geen negatieve waarden, tekst of een getal met twintig decimalen. Verwacht u een productstatus? Sta alleen bekende statussen toe.
Voorkom daarnaast dat clients velden kunnen aanpassen die zij niet mogen beheersen. Bij een profielupdate wil een gebruiker misschien naam en telefoonnummer wijzigen, maar nooit `role`, `tenantId`, kredietlimiet of prijssegment. Dit risico heet mass assignment en ontstaat vaak wanneer requestdata zonder expliciete selectie direct naar een database- of ORM-update gaat.
Parameterized queries, veilige ORM-patronen en output encoding blijven noodzakelijk om SQL-injectie en scriptinjectie te beperken. Maar vergeet businesslogica niet. Een technisch veilige request kan commercieel alsnog fout zijn wanneer een gebruiker een kortingspercentage van 10 naar 100 kan aanpassen of een retour buiten de toegestane termijn kan indienen.
Beperk misbruik zonder echte klanten te blokkeren
Rate limiting is geen luxe voor grote platforms. Het beschermt login, wachtwoordreset, couponvalidatie, voorraadchecks en checkout tegen brute force, scraping en botverkeer. Pas de limiet toe op basis van endpoint, IP-adres, account en waar nodig device-signalen. Alleen op IP limiteren is onvoldoende bij gedeelde netwerken of professionele botnetwerken.
De afweging zit in de grens. Een te strakke limiet blokkeert legitieme pieken, bijvoorbeeld wanneer een inkoopteam tegelijk orders invoert. Een te ruime limiet maakt aanvallen goedkoop. Meet normaal gedrag en kies verschillende regels voor publieke catalogusdata, authenticatie en muterende endpoints.
Zware acties kunnen extra bescherming vragen: CAPTCHA na afwijkend gedrag, tijdelijke blokkades, step-up-authenticatie voor financiële wijzigingen of handmatige beoordeling van opvallende retouren. Niet iedere frictie schaadt conversie. Gerichte frictie op hoog risico beschermt juist de marge en beschikbaarheid voor echte klanten.
Geheimen horen niet in code, browsers of chatberichten
API-keys, databasewachtwoorden, OAuth-secrets en signing keys mogen niet in repositories, frontendbundles, ticketingtools of losse spreadsheets terechtkomen. Een secret in een publieke JavaScript-bundle is geen secret. Een omgevingsvariabele op de buildserver is evenmin automatisch veilig als iedereen bij de logs kan.
Gebruik een centrale secrets-oplossing, scheid development, staging en productie strikt en hanteer minimale rechten voor services. Een CMS-integratie die alleen producten leest, krijgt geen beheerrechten op orders. Registreer bovendien wie een secret gebruikt en wanneer deze is geroteerd.
Dit is vooral relevant bij headless commerce. De frontend moet snel zijn, maar mag nooit directe toegang krijgen tot backoffice-credentials. Plaats gevoelige operaties achter een gecontroleerde serverlaag, bijvoorbeeld via Next.js server-side routes of een afzonderlijke API-service. Zo houdt u validatie, autorisatie, logging en throttling op één plek onder controle.
Logging moet fraude en fouten zichtbaar maken
Zonder bruikbare logs ontdekt u een incident pas wanneer een klant belt of omzet wegvalt. Leg beveiligingsrelevante gebeurtenissen vast: mislukte logins, tokenvernieuwingen, privilegewijzigingen, afwijkende API-fouten, wijzigingen in betaal- of bankgegevens en bulkexports van klantdata.
Log geen wachtwoorden, volledige tokens, betaalgegevens of onnodig volledige persoonsgegevens. Logging moet onderzoek mogelijk maken zonder zelf een nieuw datalek te creëren. Koppel meldingen aan concrete patronen, zoals honderden mislukte logins, ongebruikelijke datavolumes of een service account dat buiten kantooruren massaal records ophaalt.
Een goed incidentproces bevat ook beslisrechten. Wie mag tokens intrekken? Wie schakelt een integratie uit? Wie beoordeelt klantimpact? Techniek zonder eigenaarschap leidt bij druk alsnog tot vertraging.
Maak security onderdeel van uw releaseproces
API-beveiliging is geen eenmalige pentest vlak voor livegang. Nieuwe endpoints, gewijzigde rollen, externe apps en snelle feature-releases veranderen voortdurend het risico. Bouw controles in het ontwikkelproces in: code reviews voor autorisatie, geautomatiseerde tests voor toegangsrechten, dependency-scans en periodieke penetratietests op kritieke flows.
Test niet alleen of een gebruiker een endpoint kan gebruiken. Test juist of een gebruiker dat endpoint niet kan gebruiken voor data van een andere organisatie, met een andere rol of buiten de normale procesvolgorde. Die negatieve tests leveren vaak meer op dan een dashboard vol groene checks.
Voor organisaties die hun webapp als omzetkanaal en operationele infrastructuur behandelen, is API-beveiliging geen rem op groei. Het is de voorwaarde om nieuwe koppelingen, klantportalen en automatisering met controle uit te rollen. Bouw die controle voordat schaal en complexiteit u daartoe dwingen.