Veilig bouwen met een klein team: code review, SAST en dependency-checks
Terug naar blog

Veilig bouwen met een klein team: code review, SAST en dependency-checks

Bijgewerkt 8 min leestijd

Je hebt geen security-afdeling nodig om veilig op te leveren. Je hebt een klein aantal vaste gewoontes nodig, en tooling die ze afdwingt.

Je hebt geen security-afdeling nodig om veilig op te leveren. Je hebt een klein aantal vaste gewoontes nodig, en tooling die ze afdwingt.

Wij zijn een klein team senior developers. Geen security-team, geen aparte QA-laag, geen projectmanager die een proces bewaakt. Toch leveren we Magento-, Shopify- en Laravel-projecten op die een audit doorstaan. Dat lukt omdat de belangrijkste checks geautomatiseerd zijn en de rest in een korte review-routine zit.

Hieronder lees je hoe zo'n opzet eruitziet. Het is bruikbaar voor ons, voor jouw interne team of als vraag aan het bureau dat jouw webshop bouwt.

Het principe: automatiseer wat kan, review wat moet

Een klein team heeft weinig tijd. Dus verdeel je het werk zo:

  • Machines vangen de herhaalbare fouten: kwetsbare dependencies, gelekte secrets, bekende gevaarlijke patronen, type-fouten.
  • Mensen beoordelen wat een machine niet snapt: toegangslogica, bedrijfsregels, ontwerpkeuzes.

Een reviewer die zijn tijd kwijt is aan "je mist een null-check" heeft geen aandacht meer voor "deze endpoint laat iedere ingelogde gebruiker elke order opvragen". Laat tools het eerste doen.

Laag 1: code review met een korte security-checklist

Elke wijziging naar main gaat via een pull request, bekeken door een tweede persoon. Ook als je haast hebt. Zeker als je haast hebt.

Een review-checklist die in een minuut gelezen is, werkt beter dan een document van tien pagina's. Dit staat bij ons in het pull request-template:

  • Toegang. Wie mag dit aanroepen? Wordt dat server-side gecontroleerd, niet alleen in de interface? Kan gebruiker A bij gegevens van gebruiker B door een ID te wijzigen?
  • Input. Wordt alle invoer gevalideerd? Gaan queries via parameters of de ORM, nooit via string-concatenatie?
  • Output. Wordt uitvoer in de juiste context geëscaped? Is er nieuwe {!! !!}, |raw of innerHTML?
  • Secrets. Staat er een sleutel, token of wachtwoord in de code, config of testdata?
  • Bestanden. Worden uploads gecontroleerd en buiten de webroot of zonder uitvoerrechten opgeslagen?
  • Nieuwe dependency. Is die nodig, onderhouden en gecontroleerd? Zie software supply chain.
  • Foutafhandeling. Lekt een foutmelding interne details? Faalt de code veilig (toegang weigeren bij twijfel)?
  • Logging. Wordt een gevoelige actie vastgelegd, zonder gevoelige data in de log?
  • Betaling en checkout. Raakt dit scripts of velden op de betaalpagina? Dan extra aandacht, zie PCI DSS 4.0.

Regels voor het proces:

  • Wijzigingen aan authenticatie, autorisatie, betalingen en de pipeline krijgen altijd een grondige review.
  • Kleine pull requests. Een reviewer die 2000 regels moet lezen, keurt goed zonder te lezen.
  • De auteur kan niet zijn eigen wijziging goedkeuren, ook niet als hij de enige senior is. Dan vraagt hij een collega of een externe reviewer.

Laag 2: statische analyse met PHPStan en Psalm

Statische analyse leest je PHP zonder het uit te voeren en vindt typefouten, onmogelijke condities en niet-afgehandelde gevallen. Dat lijkt geen security, maar veel kwetsbaarheden beginnen als een type-fout of een onverwachte null.

  • PHPStan is de bekendste. Voor Laravel is er een extensie die Eloquent en facades begrijpt.
  • Psalm is een alternatief en heeft een ingebouwde taint analysis: het volgt data van een bron (zoals $_GET) naar een gevaarlijke bestemming (zoals een SQL-query) en meldt als er geen sanering tussen zit.

Praktische tips:

  • Begin op een niveau dat je projecten aankunnen en verhoog dat langzaam. Een baseline-bestand zet bestaande fouten opzij, zodat nieuwe code wel streng wordt beoordeeld.
  • Laat de CI falen bij nieuwe fouten. Een waarschuwing die niemand leest, doet niets.
  • Magento-code met veel dynamische generatie (factories, plugins, interceptors) geeft ruis. Richt je op je eigen modules en gebruik de Magento-specifieke ondersteuning of een passende configuratie.
bash
vendor/bin/phpstan analyse --memory-limit=1G

Laag 3: SAST met Semgrep

SAST (static application security testing) zoekt naar onveilige patronen in broncode. Semgrep is daarvoor een praktische keuze voor kleine teams: regels lezen als de code zelf, en je kunt ze eenvoudig uitbreiden.

Wat je ermee vindt:

  • gebruik van eval, unserialize op onbetrouwbare data, exec/shell_exec met variabelen
  • raw SQL met geconcateneerde variabelen
  • uitgeschakelde TLS-controle in HTTP-clients
  • gevaarlijke patronen zoals innerHTML met onbetrouwbare data
  • hardcoded secrets (deels)

Eerlijk over de beperkingen:

  • SAST geeft false positives. Als elke run veertig meldingen oplevert waarvan er drie echt zijn, schakelt je team het uit. Begin met een kleine, nauwkeurige regelset en breid uit.
  • SAST begrijpt je bedrijfslogica niet. Een endpoint zonder toegangscontrole ziet er syntactisch correct uit.
  • Het vervangt geen review en geen pentest.

Een zinvolle aanpak: draai Semgrep op elk pull request, laat alleen nieuwe bevindingen blokkeren, en bekijk de rest periodiek.

Laag 4: dependency-checks

Het grootste deel van je code is niet van jou. Zie ook Magento-extensies veilig installeren.

bash
composer audit
npm audit --omit=dev
  • composer audit (Composer 2.4 en hoger) vergelijkt je packages met bekende advisories.
  • Draai het bij elk pull request en ook op een schema, omdat nieuwe kwetsbaarheden verschijnen zonder dat jouw code verandert.
  • Gebruik een tool als Dependabot of Renovate voor automatische update-voorstellen, in kleine pull requests die door de pipeline worden getest.
  • Commit lockfiles en gebruik composer install en npm ci in CI en productie.

Een gemelde kwetsbaarheid in een package betekent niet altijd dat jij kwetsbaar bent. De vraag is of je de kwetsbare functie gebruikt. Maar beoordeel dat bewust, schrijf op waarom je iets laat staan en kom erop terug.

Laag 5: secrets-scanning

Een uitgelekt API-token in een repository is een van de simpelste en meest voorkomende fouten.

  • Gebruik een secrets-scanner (bijvoorbeeld Gitleaks of TruffleHog) als pre-commit hook en in CI. De hook voorkomt dat het erin komt, CI vangt wat de hook mist.
  • Scan ook de git-geschiedenis eenmalig voor bestaande repositories.
  • Houd .env en auth.json buiten git.
  • Is er toch iets gelekt? Roteer het secret. Verwijderen uit de repository is niet genoeg, want de geschiedenis en eventuele forks houden het.

Laag 6: staging met gemaskeerde productiedata

Een staging-omgeving met een kopie van de productiedatabase is handig en gevaarlijk. Klantgegevens op een slechter beveiligde omgeving zijn een datalek in wording. Dat is ook een AVG-kwestie.

Dit doen we in plaats daarvan:

  • Maskeer persoonsgegevens bij het kopiëren: namen, e-mailadressen, telefoonnummers, adressen, betaalgegevens. Vervang door neppe maar realistische waarden.
  • Haal e-mailadressen weg of leid ze om, zodat staging nooit echte klanten mailt.
  • Gebruik testmodus van betaalproviders, nooit live-sleutels op staging.
  • Zet staging achter authenticatie (IP-beperking of wachtwoord), zodat zoekmachines en bots er niet bij kunnen.
  • Gebruik andere secrets dan op productie.
  • Ruim oude dumps op. Een databasedump op een laptop is ook productiedata.

Een eenvoudige maskering is al veel waard. Perfect hoeft niet; de grootste risico's zijn onbeschermde e-mailadressen en betaalgegevens.

Laag 7: deploys met minimale rechten

De pijplijn is zelf een doelwit, zie het artikel over de supply chain. Kort:

  • Deployen gebeurt via CI, niet vanaf een laptop.
  • Eén deploy-key met alleen de rechten die hij nodig heeft, per omgeving.
  • De applicatie draait onder een gebruiker die niet kan schrijven naar de eigen code. Schrijfrechten alleen waar nodig, zoals cache, sessies en uploads.
  • De databasegebruiker van de applicatie kan geen schema's aanpassen of andere databases lezen. Migraties draaien met een apart account.
  • Persoonlijke accounts op servers, geen gedeelde wachtwoorden. Toegang weghalen als iemand vertrekt.
  • Bij Magento: productiemodus, app/etc/env.php niet leesbaar voor anderen, admin beschermd zoals in Magento admin beveiligen.

Beperkte rechten maken niet alle aanvallen onmogelijk, maar wel de schade kleiner. Een geslaagde RCE op een applicatie die niet naar zijn eigen code kan schrijven, is een stuk lastiger te laten overleven.

Hoe het eruitziet in de pipeline

Een compact beeld van wat bij elke pull request draait:

StapToolBlokkeert merge bij
Stijl en typenPHPStan of PsalmNieuwe fouten
TestsPHPUnit / PestFalende tests
SASTSemgrepNieuwe bevindingen met hoge zekerheid
Dependenciescomposer audit, npm auditBekende kwetsbaarheden zonder uitzondering
SecretsGitleaks of vergelijkbaarElke vondst
ReviewEen tweede persoonOntbrekende goedkeuring

Deze set kost een paar uur om op te zetten en draait vanzelf. Het is geen volledige beveiliging. Het is de ondergrens die bij elk project hoort.

Wat je niet hoeft te doen

Eerlijk is ook: sommige dingen zijn voor een klein team overkill.

  • Een eigen security operations center. Gebruik een goede logdienst en een paar alerts, zie security logging.
  • Alle tools tegelijk invoeren. Begin met dependency-checks, secrets-scanning en review. Voeg SAST en statische analyse toe zodra de basis loopt.
  • Threat modelling op elke kleine wijziging. Doe het bij nieuwe functies met gevoelige data of nieuwe koppelingen.

Wat niet in je team zit, kun je inkopen: een periodieke pentest of security audit door iemand die jouw code niet schreef. Interne controle vindt veel, een tweede paar ogen vindt de rest. Voor maatwerkcode is het ook handig om vooraf eisen vast te leggen, zie OWASP ASVS.

Veelgestelde vragen

Hebben we als klein team echt SAST nodig?

Niet per se meteen. Begin met code review, composer audit en secrets-scanning, want die leveren het meeste per uur werk. SAST voeg je toe als de basis loopt en je team tijd heeft om de meldingen te beoordelen.

Wat is het verschil tussen PHPStan en Semgrep?

PHPStan en Psalm analyseren types en logica en vinden fouten die vaak ook security-impact hebben. Semgrep zoekt gericht naar onveilige patronen. Ze vullen elkaar aan. Psalm kan daarnaast data volgen van input naar gevaarlijke functies (taint analysis).

Is een kopie van productie op staging toegestaan?

Alleen als je persoonsgegevens maskeert en de omgeving net zo goed beschermt als productie. Zonder maskering is staging met echte klantdata een datalek-risico en een AVG-probleem. Maskeren is de veiligere standaard.

Hoe vaak moeten we dependencies updaten?

Security-updates direct, andere updates in een vaste cadans, bijvoorbeeld maandelijks. Kleine, regelmatige updates zijn goedkoper en veiliger dan één grote sprong na een of twee jaar.

Kan code review een pentest vervangen?

Nee. Review vangt fouten in ontwerp en logica tijdens het bouwen. Een pentest toetst van buiten wat een aanvaller echt kan bereiken. Je wilt beide, op verschillende momenten.

Wil je weten hoe wij projecten bouwen en opleveren, of wil je dat iemand meekijkt naar de ontwikkelstraat van je eigen team? Neem contact op via /contact of bekijk onze security-aanpak.

Ruthger Idema

Geschreven door Ruthger Idema

15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.

Meer over ons team →
Deel dit artikel:

Wil je jouw e-commerce naar het volgende niveau?

Plan een vrijblijvend gesprek met onze experts over Magento, Shopify of Laravel maatwerk.

Plan een Tech Check