Terug naar blog
Web Security 5 Feb 2026 · 25 min lezen

OWASP Top 10 2025: Kritieke Risico's voor Webapplicaties

H

Hakobjan Dev Team

Security & Software Engineers

De OWASP Top 10 is de meest gezaghebbende lijst van beveiligingsrisico's voor webapplicaties. De 2025-editie brengt belangrijke verschuivingen: broken access control blijft #1, maar server-side request forgery en software supply chain risico's zijn flink gestegen. In dit uitgebreide artikel bespreken we alle tien categorieën met praktische voorbeelden en oplossingen.



A01: Broken Access Control

Broken Access Control is al jaren de meest voorkomende kwetsbaarheid. Het komt neer op het falen om af te dwingen dat gebruikers alleen mogen doen waarvoor ze geautoriseerd zijn. Denk aan IDOR (Insecure Direct Object References), privilege escalation en het omzeilen van access controls.

De oplossing begint bij een robuust authorisatie-framework: gebruik role-based of attribute-based access control (RBAC/ABAC), valideer elke request server-side, en vertrouw nooit op client-side checks alleen. Deny by default: als een gebruiker geen expliciete rechten heeft, wordt toegang geweigerd.

javascript
// Voorbeeld: IDOR kwetsbaarheid
// FOUT - gebruiker kan elke order opvragen
app.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findById(req.params.id);
  res.json(order); // Geen check of order van deze user is!
});

// GOED - authorisatie check toevoegen
app.get('/api/orders/:id', auth, async (req, res) => {
  const order = await Order.findOne({
    _id: req.params.id,
    userId: req.user.id  // Alleen eigen orders
  });
  if (!order) return res.status(404).json({ error: 'Niet gevonden' });
  res.json(order);
});

A02: Cryptographic Failures

Cryptographic Failures (voorheen "Sensitive Data Exposure") gaat over het falen bij het beschermen van data in transit en at rest. Denk aan wachtwoorden opgeslagen in plain text, gebruik van verouderde hash-algoritmes zoals MD5 of SHA1, ontbrekende TLS, of hardcoded encryption keys in broncode.

Gebruik altijd sterke algoritmes: bcrypt of Argon2 voor wachtwoorden, AES-256-GCM voor encryptie, TLS 1.3 voor data in transit. Sla nooit gevoelige data onnodig op en classificeer je data om te bepalen welke bescherming nodig is.

javascript
// FOUT - wachtwoord opslaan met MD5
const hash = crypto.createHash('md5').update(password).digest('hex');

// GOED - bcrypt gebruiken met salt rounds
const bcrypt = require('bcrypt');
const saltRounds = 12;
const hash = await bcrypt.hash(password, saltRounds);

// Verificatie
const isValid = await bcrypt.compare(inputPassword, storedHash);

A03: Injection

Injection-aanvallen ontstaan wanneer onbetrouwbare data als onderdeel van een command of query naar een interpreter wordt gestuurd. SQL injection is het bekendst, maar ook NoSQL injection, OS command injection en LDAP injection vallen in deze categorie.

Gebruik altijd parameterized queries of prepared statements. Gebruik ORM's die automatisch escaping toepassen. Valideer en sanitize alle input server-side. Voor OS commands: vermijd exec() en gebruik specifieke library-functies.

javascript
// FOUT - SQL injection kwetsbaarheid
const query = `SELECT * FROM users WHERE id = ${req.params.id}`;
db.query(query);

// GOED - parameterized query
const query = 'SELECT * FROM users WHERE id = ?';
db.query(query, [req.params.id]);

// ORM voorbeeld (Sequelize)
const user = await User.findOne({
  where: { id: req.params.id }
});

A04: Insecure Design

Insecure Design is een breed begrip dat wijst op fundamentele ontwerpfouten. Het verschil met implementatiebugs is belangrijk: een perfect geïmplementeerde onveilige architectuur is nog steeds onveilig. Denk aan een wachtwoord-reset flow die via security questions werkt (antwoorden zijn vaak te raden), of een e-commerce app zonder rate limiting op coupon-codes.

De oplossing: gebruik threat modeling vroeg in het ontwikkelproces. Implementeer secure design patterns zoals defence-in-depth, least privilege en fail-safe defaults. Test met abuse cases, niet alleen happy paths.

javascript
// FOUT - geen rate limiting op wachtwoord reset
app.post('/api/reset-password', async (req, res) => {
  const user = await User.findByEmail(req.body.email);
  if (user) sendResetEmail(user); // Geen limiet!
  res.json({ message: 'Check je email' });
});

// GOED - rate limiting + account lockout
const rateLimit = require('express-rate-limit');
const resetLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minuten
  max: 3,                    // max 3 pogingen
  message: 'Te veel verzoeken, probeer later opnieuw'
});
app.post('/api/reset-password', resetLimiter, async (req, res) => {
  // ... veilige implementatie
});

A05: Security Misconfiguration

Security Misconfiguration is de meest breed voorkomende issue. Het omvat ontbrekende security hardening, onnodige features ingeschakeld, standaard accounts en wachtwoorden, te informatieve error-berichten, en verkeerd geconfigureerde HTTP security headers.

Automatiseer je server-configuratie met Infrastructure as Code. Verwijder onnodige features, poorten en services. Implementeer security headers (CSP, HSTS, X-Frame-Options). Gebruik minimale rechten en draai geen root-processen.

yaml
# Nginx security headers configuratie
server {
  # Strict Transport Security
  add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;

  # Content Security Policy
  add_header Content-Security-Policy "default-src 'self'; script-src 'self'" always;

  # Voorkom clickjacking
  add_header X-Frame-Options "SAMEORIGIN" always;

  # Voorkom MIME type sniffing
  add_header X-Content-Type-Options "nosniff" always;

  # Verberg server versie
  server_tokens off;
}

A06: Vulnerable & Outdated Components

Moderne applicaties bevatten tientallen tot honderden dependencies. Elke daarvan kan kwetsbaarheden bevatten. In 2024 werden meer dan 29.000 nieuwe CVE's gepubliceerd. Het bijhouden hiervan zonder tooling is onmogelijk.

Gebruik Software Composition Analysis (SCA) tools zoals Snyk, npm audit of Dependabot. Verwijder ongebruikte dependencies. Pin je versies en update regelmatig. Monitor voor nieuwe CVE's die jouw stack raken en heb een patch-strategie klaar.

bash
# Controleer kwetsbaarheden in je project
npm audit

# Automatisch kwetsbare packages fixen
npm audit fix

# Snyk scan voor diepere analyse
npx snyk test

# Verouderde packages tonen
npm outdated

# Dependabot config (.github/dependabot.yml)
version: 2
updates:
  - package-ecosystem: "npm"
    directory: "/"
    schedule:
      interval: "weekly"

A07: Identification & Authentication Failures

Authentication failures omvatten brute-force aanvallen, credential stuffing, zwakke wachtwoord-policies, ontbrekende multi-factor authenticatie (MFA) en slecht sessie-management. Session fixation, session hijacking en het niet invalideren van sessions bij logout zijn veelgemaakte fouten.

Implementeer MFA waar mogelijk, gebruik sterke wachtwoord-policies (minimaal 8 tekens, check tegen leaked password databases), en gebruik proven session management frameworks. Beperk login-pogingen en implementeer account lockout mechanismes.

javascript
// Login met brute-force bescherming
const loginAttempts = new Map();

app.post('/api/login', async (req, res) => {
  const { email, password } = req.body;
  const attempts = loginAttempts.get(email) || { count: 0, lockUntil: 0 };

  // Check lockout
  if (attempts.lockUntil > Date.now()) {
    return res.status(429).json({ error: 'Account tijdelijk geblokkeerd' });
  }

  const user = await User.findByEmail(email);
  const valid = user && await bcrypt.compare(password, user.password);

  if (!valid) {
    attempts.count++;
    if (attempts.count >= 5) {
      attempts.lockUntil = Date.now() + 15 * 60 * 1000; // 15 min lock
    }
    loginAttempts.set(email, attempts);
    return res.status(401).json({ error: 'Ongeldige inloggegevens' });
  }

  loginAttempts.delete(email);
  const token = generateJWT(user);
  res.json({ token });
});

A08: Software & Data Integrity Failures

Deze categorie richt zich op aannames over software-updates, kritieke data en CI/CD pipelines zonder integriteitsverificatie. Denk aan de SolarWinds-aanval: aanvallers compromitteerden het build-systeem en voegden malware toe aan legitieme software-updates die door duizenden organisaties werden geïnstalleerd.

Gebruik Subresource Integrity (SRI) voor externe scripts en stylesheets. Teken software-releases digitaal. Beveilig je CI/CD pipeline met code signing, pipeline-as-code met code reviews, en gescheiden build-omgevingen.

javascript
// Subresource Integrity (SRI) voor externe scripts
<script
  src="https://cdn.example.com/lib.min.js"
  integrity="sha384-oqVuAfXRKap7fdgcCY5uykM6+R9GqQ8K/uxAh6VgnSY"
  crossorigin="anonymous">
</script>

// Lock file verificatie in CI pipeline
// package-lock.json of yarn.lock ALTIJD committen
// Gebruik npm ci in plaats van npm install in CI
npm ci --ignore-scripts  // Voorkom post-install scripts

// Verifieer package integriteit
npm audit signatures

A09: Security Logging & Monitoring Failures

Zonder adequate logging en monitoring worden aanvallen pas ontdekt als het te laat is. Uit onderzoek blijkt dat de gemiddelde tijd om een breach te detecteren meer dan 200 dagen is. Veel organisaties loggen onvoldoende events, bewaren logs niet lang genoeg, of monitoren ze niet actief.

Log alle authenticatie-events (inlog, uitlog, mislukte pogingen), access control failures, input validation failures en server-side fouten. Centraliseer logs met tools als ELK Stack of Grafana Loki. Stel alerting in voor verdachte patronen en test je incident response plan regelmatig.

javascript
// Gestructureerde security logging met Winston
const winston = require('winston');

const securityLogger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  defaultMeta: { service: 'auth-service' },
  transports: [
    new winston.transports.File({ filename: 'security.log' })
  ]
});

// Log mislukte login pogingen
app.post('/api/login', async (req, res) => {
  const { email } = req.body;
  const success = await authenticate(email, req.body.password);

  securityLogger.info({
    event: success ? 'LOGIN_SUCCESS' : 'LOGIN_FAILURE',
    email,
    ip: req.ip,
    userAgent: req.headers['user-agent'],
    timestamp: new Date().toISOString()
  });
});

A10: Server-Side Request Forgery (SSRF)

SSRF-aanvallen misleiden de server om requests te maken naar onbedoelde locaties. In cloud-omgevingen is dit extra gevaarlijk: aanvallers kunnen het metadata-endpoint benaderen (bijv. http://169.254.169.254 op AWS) om credentials te stelen. De Capital One-breach van 2019 was een SSRF-aanval die 100 miljoen records lekte.

Valideer en sanitize alle door de gebruiker aangeleverde URL's. Gebruik een allowlist van toegestane domeinen en protocollen. Blokkeer requests naar private IP-ranges en cloud metadata endpoints. Gebruik network-level segmentatie om de blast radius te beperken.

javascript
// FOUT - user-supplied URL zonder validatie
app.post('/api/fetch-url', async (req, res) => {
  const response = await fetch(req.body.url); // SSRF!
  res.json(await response.json());
});

// GOED - URL validatie met allowlist
const allowedDomains = ['api.example.com', 'cdn.example.com'];

function isAllowedUrl(urlString) {
  try {
    const url = new URL(urlString);
    if (!['http:', 'https:'].includes(url.protocol)) return false;
    if (!allowedDomains.includes(url.hostname)) return false;
    // Blokkeer private IP ranges
    const ip = url.hostname;
    if (ip.startsWith('10.') || ip.startsWith('192.168.') ||
        ip.startsWith('169.254.') || ip === 'localhost') return false;
    return true;
  } catch { return false; }
}

app.post('/api/fetch-url', async (req, res) => {
  if (!isAllowedUrl(req.body.url)) {
    return res.status(400).json({ error: 'URL niet toegestaan' });
  }
  const response = await fetch(req.body.url);
  res.json(await response.json());
});

Praktische Beveiligingsstrategie

Gebruik de OWASP Top 10 als startpunt voor je security roadmap, niet als eindbestemming. Begin met een threat model voor je applicatie: welke data is het meest waardevol? Wie zijn potentiële aanvallers? Welke attack vectors zijn het meest waarschijnlijk?

Integreer security testing in je CI/CD pipeline met tools als OWASP ZAP (DAST), Semgrep (SAST) en Snyk (SCA). Automatiseer wat je kunt, en plan regelmatige penetratietests voor wat je niet kunt automatiseren.

Pro Tip

Voer na elke deployment een automated security scan uit. Tools als OWASP ZAP kunnen als stap in je CI/CD pipeline draaien en automatisch kwetsbaarheden rapporteren vóórdat code in productie komt.

Deel dit artikel

Alle artikelen