Skip to content
Terug naar blog
Beveiliging

Essentiële webbeveiliging: hashing, validatie en authenticatie

Essentiële webbeveiliging: bcrypt vs Argon2, XSS- en SQL-injectiepreventie, aanbevolen aanpak voor JWT, CSP en MFA — met JS-voorbeelden.

12 min leestijd

Aanbevolen beveiligingsaanpak voor webontwikkelaars

Webbeveiliging is niet optioneel. Door de toenemende cyberdreigingen moeten ontwikkelaars beveiliging in elke laag van hun applicaties inbouwen. Deze gids behandelt essentiële praktijken die je vandaag nog kunt toepassen.

Wachtwoordbeveiliging

Sla nooit platte wachtwoorden op

Maak altijd een hash van wachtwoorden met moderne algoritmen zoals bcrypt, Argon2 of scrypt. Deze algoritmen zijn bewust traag ontworpen, zodat brute-force-aanvallen niet praktisch uitvoerbaar zijn.

// Good: Using bcrypt
const bcrypt = require('bcrypt');
const hash = await bcrypt.hash(password, 12);

Vergelijking van hash-algoritmen

Niet alle hash-algoritmen zijn gelijk. De juiste keuze hangt af van je dreigingsmodel en gebruiksscenario:

AlgoritmeUitvoergrootteSnelheidToepassingBeveiligingsstatus
MD5128-bitZeer snelChecksums, non-security hashesGebroken voor beveiliging
SHA-256256-bitSnelData-integriteit, digitale handtekeningenVeilig
bcrypt184-bitTraag (instelbaar)WachtwoordopslagVeilig
Argon2ConfigureerbaarTraag (instelbaar)Wachtwoordopslag (modern)Aanbevolen voor nieuwe projecten

bcrypt en Argon2 zijn met opzet traag — dit is een feature, geen bug. Elke hash-bewerking duurt tientallen tot honderden milliseconden, waardoor grootschalige brute-force-aanvallen economisch onhaalbaar worden.

Wachtwoord-entropie begrijpen

Wachtwoordsterkte is wiskundig te meten met entropie: entropy = log2(charset_size^length). Een wachtwoord van 8 tekens met alleen kleine letters (26 tekens) heeft ~37,6 bits entropie. Een wachtwoord van 16 tekens met hoofdletters, kleine letters, cijfers en symbolen (95 tekens) heeft ~105 bits — exponentieel moeilijker te kraken. Daarom telt voor de meeste gebruikers lengte zwaarder dan complexiteit. Voor een diepere duik in de wiskunde achter wachtwoordsterkte, lees onze gids wachtwoord-entropie uitgelegd.

Gebruik een wachtwoordbeheerder

Adviseer je gebruikers om een wachtwoordbeheerder te gebruiken. Wachtwoorden die mensen zelf kiezen volgen vaak voorspelbare patronen waar aanvallers met woordenboekaanvallen op inspelen. Wachtwoordbeheerders genereren echt willekeurige strings en voorkomen hergebruik van wachtwoorden tussen verschillende diensten — een van de meest gangbare aanvalsroutes voor credential stuffing.

Gebruik voldoende salt-rondes

Salt-rondes bepalen de rekenkosten. Hoger is veiliger, maar trager. 10-12 rondes is voor de meeste applicaties een goede balans.

Invoervalidatie

Valideer zowel aan client- als serverzijde

Client-side validatie verbetert de UX, maar server-side validatie is essentieel voor beveiliging. Vertrouw nooit op invoer van de client.

Saneer alle gebruikersinvoer

Voorkom injectie-aanvallen door invoer te saneren:

  • Gebruik parameterized queries voor SQL
  • Escape HTML-uitvoer om XSS te voorkomen
  • Valideer bestandsuploads streng

Concrete aanvalsvoorbeelden

Door echte aanvallen te begrijpen, kun je je er beter tegen verdedigen. Stel: een reactieformulier rendert gebruikersinvoer rechtstreeks in HTML. Een aanvaller verstuurt:

<script>alert('xss')</script>

Als de applicatie dit zonder te escapen rendert, voert het script zich uit in de browser van elke bezoeker — cookies stelen, gebruikers omleiden of keyloggers injecteren. De oplossing: encodeer uitvoer altijd contextafhankelijk. Gebruik libraries zoals DOMPurify voor HTML-sanering.

SQL-injectie is even gevaarlijk. Bij een inlogformulier voert een aanvaller de gebruikersnaam in:

' OR 1=1 --

Als de query met stringconcatenatie wordt opgebouwd ("SELECT * FROM users WHERE username='" + input + "'"), omzeilt dit de authenticatie volledig. De -- becommentarieert de rest van de query. De oplossing: gebruik altijd parameterized queries (ook wel prepared statements genoemd). Alle grote databasebibliotheken ondersteunen ze:

// WRONG: String concatenation
db.query(`SELECT * FROM users WHERE username='${input}'`);

// RIGHT: Parameterized query
db.query('SELECT * FROM users WHERE username = $1', [input]);

Content Security Policy (CSP)

Als extra verdedigingslaag (defense-in-depth) kun je Content Security Policy-headers inzetten. CSP vertelt de browser welke contentbronnen vertrouwd zijn en blokkeert effectief inline scripts en ongeautoriseerd laden van resources. Zelfs als er een XSS-kwetsbaarheid in je code zit, kan een strikte CSP voorkomen dat het geïnjecteerde script wordt uitgevoerd. Begin met Content-Security-Policy: default-src 'self' en voeg geleidelijk uitzonderingen toe waar nodig.

Hashfuncties

Kies de juiste hash

Verschillende use cases vragen om verschillende hashfuncties:

Use caseAanbevolen
Wachtwoordenbcrypt, Argon2
IntegriteitSHA-256
ChecksumsSHA-256, MD5 (niet voor beveiliging)
Snelle hash-berekeningBLAKE3

Hash-uitvoer en collisions begrijpen

MD5 produceert een 128-bit hash (32 hex-tekens), terwijl SHA-256 een 256-bit hash (64 hex-tekens) oplevert. Dat verschil doet ertoe: een grotere uitvoerruimte betekent exponentieel meer mogelijke hashwaarden, waardoor collisions veel onwaarschijnlijker worden. Een collision ontstaat wanneer twee verschillende invoeren dezelfde hash opleveren — een aanvaller die collisions kan fabriceren, kan digitale handtekeningen vervalsen of geverifieerde data manipuleren.

MD5-collisions zijn op moderne hardware binnen seconden te genereren. SHA-256 blijft collision-resistant zonder bekende praktische aanvallen. Daarom is het kiezen van het juiste algoritme voor de juiste context cruciaal:

  • Checksums en deduplicatie: MD5 is acceptabel als beveiliging geen rol speelt
  • Data-integriteit en handtekeningen: SHA-256 biedt sterke weerstand tegen collisions
  • Wachtwoordopslag: bcrypt of Argon2, die salt en bewuste traagheid toevoegen

HMAC voor berichtauthenticatie

Wanneer je zowel de integriteit als de authenticiteit van een bericht wilt verifiëren, gebruik je HMAC (Hash-based Message Authentication Code). HMAC combineert een hashfunctie met een geheime sleutel, zodat alleen partijen die de sleutel kennen de tag kunnen genereren of verifiëren. Dit is essentieel voor API-authenticatie, webhook-verificatie en veilige tokengeneratie.

Gebruik nooit MD5 of SHA-1 voor beveiliging

MD5 en SHA-1 zijn gebroken voor beveiligingsdoeleinden. Gebruik SHA-256 of SHA-3 voor cryptografische hashing.

HTTPS overal

Wat TLS werkelijk doet

TLS (Transport Layer Security) biedt drie cruciale beschermingen: versleuteling tijdens verzending (voorkomt afluisteren), serverauthenticatie (bewijst dat je met de echte server praat, niet met een bedrieger) en data-integriteit (detecteert manipulatie tijdens de verzending). Zonder TLS gaat alle data tussen je gebruikers en je server — wachtwoorden, tokens, persoonsgegevens — onversleuteld over de lijn.

Gebruik altijd TLS

  • Haal certificaten bij vertrouwde CA’s (Let’s Encrypt is gratis en volledig geautomatiseerd)
  • Leid HTTP om naar HTTPS
  • Gebruik HSTS-headers
  • Houd TLS-versies up-to-date

HSTS en mixed content

HTTP Strict Transport Security (HSTS)-headers vertellen browsers om uitsluitend via HTTPS te verbinden, zelfs als de gebruiker http:// intypt. Stel Strict-Transport-Security: max-age=31536000; includeSubDomains in om dit een heel jaar lang af te dwingen voor alle subdomeinen. Dit voorkomt SSL-stripping-aanvallen waarbij een aanvaller een verbinding terugbrengt naar HTTP.

Let op mixed-content-waarschuwingen: als je HTTPS-pagina afbeeldingen, scripts of stylesheets over HTTP laadt, blokkeert de browser die of geeft er een waarschuwing voor. Controleer je pagina’s op hardcoded http://-URL’s en gebruik protocol-relatieve paden of dwing HTTPS af voor alle resources.

Authenticatie

Implementeer rate limiting

Voorkom brute-force-aanvallen met rate limiting:

  • Beperk het aantal inlogpogingen per IP
  • Voeg vertragingen toe na mislukte pogingen
  • Gebruik CAPTCHA bij verdachte activiteit

Basis van JWT-authenticatie

JSON Web Tokens (JWT) bieden een stateless authenticatiemechanisme met de structuur header.payload.signature. De server ondertekent het token met een geheime sleutel en clients nemen het token op in opeenvolgende verzoeken. Omdat het token de claims van de gebruiker bevat, hoeft de server niet bij elk verzoek de sessiestatus op te zoeken — daardoor zijn JWT’s goed geschikt voor gedistribueerde systemen en microservices.

Stel altijd korte vervaltijden in op access tokens (bijvoorbeeld 15 minuten) en gebruik refresh tokens om nieuwe access tokens te verkrijgen. Sla refresh tokens veilig op (httpOnly-cookies, niet localStorage) en implementeer token-rotatie zodat elk refresh token maar één keer gebruikt kan worden.

Multi-factor authenticatie (MFA)

MFA is niet langer optioneel voor een serieuze applicatie. Een tweede factor vereisen — TOTP-codes (Google Authenticator), hardwaresleutels (YubiKey) of pushmeldingen — vermindert de impact van gecompromitteerde wachtwoorden drastisch. Zelfs als een aanvaller geldige inloggegevens bemachtigt, kan die zich zonder de tweede factor niet authenticeren.

Preventie van sessiefixatie

Sessiefixatie-aanvallen vinden plaats wanneer een aanvaller een bekende sessie-ID instelt voordat de gebruiker zich authenticeert. Na het inloggen gebruikt de aanvaller diezelfde sessie-ID om de geauthenticeerde sessie te kapen. Voorkom dit door de sessie-ID altijd opnieuw te genereren na succesvolle authenticatie en de oude ongeldig te maken.

Gebruik veilig sessiebeheer

  • Genereer cryptografisch willekeurige sessie-ID’s
  • Zet de secure- en httpOnly-flags op cookies
  • Implementeer sessietimeouts
  • Maak sessies ongeldig bij uitloggen

Checklist beveiligingsheaders

De juiste HTTP-responseheaders inzetten is een van de meest effectieve en eenvoudige manieren om je applicatie te harden. Hieronder een snelle-referentietabel met essentiële beveiligingsheaders:

HeaderDoelVoorbeeldwaarde
Content-Security-PolicyVoorkomt XSS en data-injectiedefault-src 'self'
Strict-Transport-SecurityDwingt HTTPS-verbindingen afmax-age=31536000; includeSubDomains
X-Content-Type-OptionsVoorkomt MIME-type sniffingnosniff
X-Frame-OptionsVoorkomt clickjackingDENY
Referrer-PolicyBeheert referrer-informatiestrict-origin-when-cross-origin

Deze headers zijn in te stellen op webserverniveau (Nginx, Apache), op CDN-/edge-niveau (Cloudflare, Vercel) of binnen je applicatieframework. Test je headers met tools zoals securityheaders.com. Mik op een A+-score — de meeste van deze headers zijn een enkele regel configuratie en kosten niets om te implementeren.

Onze beveiligingstools gebruiken

Verken onze beveiligingstools die je bij je ontwikkelwerk helpen:

Voor een breder beeld van hoe encoding-, hashing- en conversietools in je ontwikkelworkflow passen, kun je ook onze essentiële gids voor ontwikkeltools lezen.

Veelgestelde vragen

Wat is de meest voorkomende webbeveiligings­kwetsbaarheid?

Cross-Site Scripting (XSS) blijft volgens OWASP de meest voorkomende webkwetsbaarheid. Het ontstaat wanneer applicaties onvertrouwde data in webpagina’s opnemen zonder juiste validatie. Voorkom XSS door alle gebruikersinvoer te saneren, Content Security Policy-headers te gebruiken en uitvoer contextafhankelijk te encoderen (HTML, JavaScript, URL of CSS).

Is MD5 nog veilig voor wachtwoordopslag?

Nee — MD5 moet nooit worden gebruikt voor wachtwoordopslag. Het algoritme is rekenkundig snel, waardoor het kwetsbaar is voor brute-force- en rainbow-table-aanvallen. Moderne GPU’s kunnen miljarden MD5-hashes per seconde berekenen. Gebruik in plaats daarvan bcrypt, scrypt of Argon2, die bewust traag zijn en automatisch een salt toevoegen om aanvallen tegen te gaan.

Hoe lang moet een veilig wachtwoord zijn in 2026?

Een minimum van 12 tekens wordt aanbevolen, maar 16+ tekens biedt aanzienlijk sterkere bescherming. Lengte telt zwaarder dan complexiteit — een passphrase van 20 tekens zoals “correct-horse-battery-staple” is sterker dan een kort, complex wachtwoord zoals “P@ss1!”. Schakel multi-factor authenticatie (MFA) in voor kritieke accounts, ongeacht de wachtwoordlengte.

Wat is het verschil tussen encryptie en hashing?

Encryptie is omkeerbaar — je kunt data met een sleutel weer terug decoderen naar de oorspronkelijke vorm. Hashing is eenrichtingsverkeer — je kunt de oorspronkelijke data niet uit een hash herleiden. Gebruik encryptie voor data die je moet kunnen ophalen (zoals opgeslagen gebruikersdata) en hashing voor data die je alleen hoeft te verifiëren (zoals wachtwoorden en checksums).

Moet ik mijn eigen authenticatiesysteem bouwen?

Nee — authenticatie vanaf nul bouwen is riskant en foutgevoelig. Gebruik beproefde frameworks en diensten zoals Auth0, Firebase Auth of Supabase Auth. Die nemen wachtwoordopslag, sessiebeheer, token-rotatie, MFA en brute-force-bescherming voor je rekening. Besteed je ontwikkeltijd liever aan de unieke functies van je applicatie.

Conclusie

Beveiliging is een doorlopend proces, geen eenmalige klus. Blijf op de hoogte van nieuwe kwetsbaarheden, audit je code regelmatig en volg het principe van least privilege. Je gebruikers vertrouwen je hun data toe — eer dat vertrouwen met een degelijke beveiligingsaanpak.

Gerelateerde artikelen

Alle artikelen bekijken