Laravel neemt je veel beveiligingswerk uit handen. Niet alles. De OWASP Top 10:2025 laat per risico zien waar het framework stopt en jouw code begint.
Laravel neemt je veel beveiligingswerk uit handen. Niet alles. De OWASP Top 10:2025 laat per risico zien waar het framework stopt en jouw code begint.
Hieronder lopen we de tien categorieën langs. Per categorie: wat Laravel standaard doet, en waar developers het in de praktijk misdoen. Voor de volledige context van OWASP zie /security/owasp.
A01: Broken Access Control (inclusief SSRF)
Dit is de nummer één, en in Laravel-projecten ook de meest voorkomende fout. Laravel geeft je gates en policies. Het dwingt ze niet af.
Wat het framework biedt:
- Policies per model, gekoppeld aan
authorize()encan-middleware - Gates voor losse acties
- Route model binding
Waar het misgaat:
- Een controller haalt
Order::find($id)op zonder te checken of de order van de ingelogde gebruiker is. - Een route is wel beveiligd met
auth, maar niet met een policy. Ingelogd is niet hetzelfde als bevoegd. - Een nieuwe API-route vergeet de middleware.
// Fout: elke ingelogde gebruiker kan elke order openen
$order = Order::findOrFail($id);
// Beter: de policy beslist
$order = Order::findOrFail($id);
$this->authorize('view', $order);
SSRF zit sinds de laatste editie in deze categorie. Doet je app requests naar een URL die een gebruiker aanlevert (webhook, afbeelding importeren, preview)? Dan kan een aanvaller je server naar interne adressen laten praten. Valideer hosts tegen een allowlist en blokkeer interne IP-bereiken.
Test hierop. Schrijf per policy een test die bewijst dat gebruiker A niet bij de data van gebruiker B kan.
A02: Security Misconfiguration
Hier gaat het vaak mis door haast. Laravel heeft goede defaults, maar de configuratie in productie is van jou.
De bekendste fout: APP_DEBUG=true op een live omgeving. Dan toont Laravel bij een fout een uitgebreide foutpagina. Die kan je configuratiewaarden, paden en soms credentials laten zien.
Controleer in productie:
APP_DEBUG=falseAPP_ENV=production- Een gegenereerde, geheime
APP_KEY - Het
.env-bestand niet bereikbaar via de webserver (document root ispublic/) - Geen debugtools zoals Telescope of Debugbar open voor iedereen
root /home/app/current/public;
Wijst je root naar de projectmap in plaats van public/, dan staat je .env mogelijk gewoon online. Dat zien we vaker dan je zou denken. Vermijd het door de webroot strikt op public te zetten en dat te testen.
Een kort overzicht staat in onze Laravel security checklist.
A03: Software Supply Chain Failures
Nieuw in de 2025-lijst. Je Laravel-app bestaat grotendeels uit code van anderen: Composer-pakketten, NPM-pakketten, eventueel een Docker-image.
Wat helpt:
composer auditin CI, met een falende build bij bekende kwetsbaarheden- Het
composer.lock-bestand committen en uitrollen - Weinig, goed onderhouden pakketten in plaats van veel
- Pakketten die niet meer onderhouden worden vervangen
Waar het misgaat: pakketten die jaren niet zijn bijgewerkt, en frameworks waar je achterloopt. Een voorbeeld uit de praktijk: de kwetsbaarheid CVE-2025-54068 in Livewire v3 raakte ook Filament-apps. Lees Livewire en Filament updates voor het volledige verhaal.
Hetzelfde patroon zie je in Magento, zie extensies en supply chain-risico.
A04: Cryptographic Failures
Laravel doet veel goed. Je hoeft zelf geen cryptografie te bouwen, en dat is precies de bedoeling.
Wat het framework regelt:
Hash::make()gebruikt standaard bcrypt of Argon2 voor wachtwoordenCrypt::encryptString()versleutelt met jeAPP_KEY- Het
encrypted-cast voor Eloquent-attributen - HTTPS-afdwinging via middleware of de webserver
Waar het misgaat:
- Wachtwoorden of tokens zelf hashen met
md5ofsha1 - Gevoelige velden (bijvoorbeeld BSN, IBAN, API-sleutels van klanten) leesbaar in de database
APP_KEYin git of gedeeld tussen omgevingen- Geen HTTPS op een interne of staging-omgeving met echte data
Let op bij het wijzigen van APP_KEY. Versleutelde data en sessies zijn daarna niet meer te lezen. Plan dat dus bewust.
A05: Injection
Eloquent en de query builder gebruiken parameter bindings. SQL-injectie via de gewone methoden is daarmee grotendeels afgedekt. Blade escapet uitvoer standaard met {{ }}.
Het gaat mis bij omwegen:
// Kwetsbaar
DB::select("SELECT * FROM users WHERE email = '$email'");
// Veilig
DB::select('SELECT * FROM users WHERE email = ?', [$email]);
Let op deze plekken:
DB::raw(),whereRaw(),orderByRaw()met gebruikersinvoerorderBy($request->input('sort'))zonder allowlist op kolomnamen{!! $content !!}in Blade met data die niet van jou komt- Shell-commando's met gebruikersinvoer (
exec,shell_exec)
Voor XSS geldt: gebruik {{ }} tenzij je zeker weet dat de HTML veilig is. Moet je HTML van gebruikers tonen, gebruik dan een bewezen sanitizer en geen eigen regex.
A06: Insecure Design
Dit is geen codefout maar een ontwerpfout. Een feature werkt prima en is toch onveilig, omdat niemand over misbruik nadacht.
Voorbeelden:
- Een wachtwoord-reset die onbeperkt pogingen toestaat
- Een kortingscode-endpoint zonder limiet, waarmee je codes kunt raden
- Een export die alle klanten teruggeeft zonder logging
- Een gebruikersrol die zichzelf kan upgraden
Laravel helpt met de rate limiter, maar je moet bepalen waar die nodig is. Stel bij elke nieuwe feature één vraag: hoe misbruikt iemand dit?
Een korte sessie met het team voor je bouwt, levert meer op dan een audit achteraf. Meer over testen op dit soort fouten: /security/pentest.
A07: Authentication Failures
Laravel biedt met Breeze, Jetstream, Fortify en Sanctum degelijke bouwstenen. Wachtwoorden worden gehasht, sessies worden geregenereerd bij login en er is login-throttling.
Waar het misgaat:
- Eigen login-logica geschreven, met fouten
- Geen rate limiting op login en wachtwoord-reset
- Geen 2FA voor beheerders
- Lange levensduur van API-tokens, zonder intrekken
- Verschillende foutmeldingen voor "gebruiker bestaat niet" en "wachtwoord fout", waardoor je bestaande accounts verraadt
Gebruik waar mogelijk wat het framework levert, en schrijf geen eigen authenticatie als het niet hoeft. Zet 2FA aan voor alle beheerdersaccounts, ook in je Filament-panel.
RateLimiter::for('login', function (Request $request) {
return Limit::perMinute(5)->by($request->ip() . '|' . $request->input('email'));
});
A08: Software or Data Integrity Failures
Hier gaat het om vertrouwen in code en data zonder dat je de integriteit controleert.
In Laravel kom je dit tegen bij:
- Deserialisatie van data die niet vertrouwd is (
unserializeop invoer) - Webhooks die je accepteert zonder de handtekening te controleren
- CI/CD-pipelines waarin iedereen kan deployen
- Updates of plug-ins die zonder controle worden binnengehaald
Controleer bij elke webhook van een betaalprovider of externe dienst de signature. Accepteer de payload niet op basis van alleen een URL die "niemand kent".
// Controleer de handtekening voordat je de payload verwerkt
abort_unless(hash_equals($expected, $received), 403);
Gebruik hash_equals voor vergelijkingen van geheimen. Het voorkomt timing-aanvallen.
A09: Security Logging & Alerting Failures
Zonder logging merk je een inbraak pas als de klant belt. En dat is meestal te laat.
Laravel logt via Monolog en kan naar bestanden, syslog of externe diensten. Het framework weet alleen niet wat voor jou belangrijk is.
Log in elk geval:
- Mislukte en geslaagde logins van beheerders
- Wijzigingen in rollen en rechten
- Exports en bulkacties
- Geweigerde autorisaties (403's)
Log geen wachtwoorden, tokens of volledige betaalgegevens. Zorg verder dat iemand naar de logs kijkt, of dat een alert afgaat. Een log die niemand leest is een archief, geen bewaking.
Voor het grotere plaatje: incident response en monitoring.
A10: Mishandling of Exceptional Conditions
Ook nieuw. Het gaat om hoe je app omgaat met fouten en onverwachte situaties.
Voorbeelden uit Laravel-apps:
- Een
try/catchdie de fout negeert, waardoor een betaling als geslaagd geldt terwijl hij faalde - Een uitzondering die gevoelige gegevens in de response lekt
- Een externe API die uitvalt, waarna je code "fail open" werkt en toegang geeft
- Queue-jobs die stil mislukken zonder melding
Houd deze regel aan: bij twijfel weiger je toegang, niet verleen je die. Een mislukte autorisatiecheck mag nooit leiden tot "dan laten we het maar toe".
Zorg dat failed_jobs bewaakt wordt en dat onverwachte fouten een melding geven. Toon gebruikers een nette foutpagina, en bewaar details in je logs.
Overzicht
| OWASP 2025 | Laravel regelt | Jij doet |
|---|---|---|
| A01 Access Control | Gates, policies | Policies afdwingen, SSRF-checks |
| A02 Misconfiguration | Goede defaults | APP_DEBUG=false, webroot public/ |
| A03 Supply Chain | Composer | composer audit, updates |
| A04 Cryptographic | Hash, Crypt | Geen eigen crypto, sleutelbeheer |
| A05 Injection | Bindings, Blade-escaping | Raw queries vermijden |
| A06 Insecure Design | Rate limiter | Misbruik doordenken |
| A07 Authentication | Breeze, Fortify, Sanctum | 2FA, throttling |
| A08 Integrity | Signed URLs | Webhook-signatures |
| A09 Logging | Monolog | Wat loggen, wie kijkt |
| A10 Exceptional Conditions | Exception handler | Fail closed |
Waar begin je?
Heb je een bestaande Laravel-app en weinig tijd? Begin met deze volgorde:
- Controleer
APP_DEBUG, webroot en.env-toegang. - Draai
composer auditen update wat openstaat. - Loop alle routes na op ontbrekende autorisatie.
- Zoek naar
DB::raw,whereRawen{!! !!}. - Zet rate limiting en 2FA aan op login en beheer.
Dat zijn vijf uur werk dat meer risico wegneemt dan een los pentest zonder opvolging. Voor een diepere controle kijken we ook naar /security/audit.
Veelgestelde vragen
Is Laravel standaard veilig?
Grotendeels voor de basis: SQL-bindings, CSRF-bescherming, hashing en output-escaping zijn ingebouwd. Autorisatie, configuratie in productie, updates en logging blijven jouw verantwoordelijkheid.
Wat is de meest gemaakte fout in Laravel-apps?
Ontbrekende autorisatie. Een route is ingelogd-only, maar controleert niet of de gebruiker bij dat specifieke record mag. Dat is precies A01 Broken Access Control.
Moet ik mass assignment nog fixen?
Ja. Gebruik $fillable of $guarded bewust, en geef nooit $request->all() zonder validatie aan create() of update(). Gebruik $request->validated() of een form request.
Wat is er nieuw in de OWASP Top 10:2025?
Twee nieuwe categorieën: A03 Software Supply Chain Failures en A10 Mishandling of Exceptional Conditions. SSRF zit nu onder A01 Broken Access Control.
Hoe vaak moet ik een Laravel-app laten testen?
Bij grote wijzigingen en daarnaast periodiek, bijvoorbeeld jaarlijks voor een app met klantdata of betalingen. Een pentest zonder opvolging heeft weinig waarde, plan dus ook tijd om bevindingen te herstellen.
Wil je weten waar jouw Laravel-applicatie staat ten opzichte van deze lijst? Wij kijken mee, zeggen eerlijk wat nodig is, en geven je een concreet lijstje. Zie /security/laravel en /laravel, of stuur ons een bericht via /contact.

Geschreven door Ruthger Idema
15+ jaar ervaring in e-commerce development. Gespecialiseerd in Magento, Shopify en Laravel maatwerk.
Meer over ons team →


