03 — De voorbeeldentabel
Voorbeelden: wat de scanner zegt, en waarom
Een scanner is pas te vertrouwen als je kunt zien wat hij zegt in de gevallen waar het moeilijk wordt. Hier staan ze allemaal, met het oordeel dat we verwachten en de uitslag die de scanner letterlijk geeft.
Hoe je de tabel leest
Elke rij begint bij een site die alle controles haalt: HTTPS met een geldig certificaat, een doorverwijzing van http naar https, alle beveiligingsheaders, een SPF-record dat eindigt op -all, DMARC op p=reject, en een homepage met een taal, een titel, een hoofdkop, een plaatje met alt-tekst en een invulveld met label. Per rij veranderen we precies één ding. Daarom staat in de kolom Situatie alleen wat afwijkt.
De kolom Oordeel is wat we vooraf verwachtten:
- Afkeur: dit moet je oplossen. Er is een concreet risico of een wettelijke verplichting.
- Advies: dit kan beter. Het is gangbaar, maar er is een beter alternatief.
- In orde: niets te doen.
- Niet gemeten: we hadden niet wat we nodig hadden om te oordelen, en de reden staat erbij.
- Niet van toepassing: de controle hoort niet bij deze site (geen WordPress, geen afbeeldingen, geen formulier).
Wat de tabel niet laat zien
De scanner kijkt alleen naar de homepage, naar de headers die de server meestuurt en naar openbare DNS-records. Hij voert geen JavaScript uit, logt niet in en probeert niets uit. Cookies die pas door JavaScript worden gezet, ziet hij dus niet. Daarom is er een aparte controle die de trackers in de HTML zoekt. Een volledige toegankelijkheidstoets volgens WCAG is dit niet: we controleren zes basispunten die je zonder browser kunt vaststellen.
Deze pagina is opgesteld met hulp van een AI-model. De uitslagen in de tabel komen uit de scanner zelf, de bronnen staan op de werkwijzepagina.
Waarom deze tabel
De tabel is de specificatie
We hebben deze tabel geschreven vóór de code. Elke rij is een situatie die iemand die websites onderhoudt als eerste zou uitproberen: precies op een drempel, net eronder, een nulgeval, een record dat dubbel staat, een versie die we niet kennen. Wie twijfelt aan een oordeel van de scanner, vindt hier welke situatie dat oordeel oplevert, en waarom.
De kolom Uitslag van de scanner is niet met de hand overgetypt: die is gemaakt door de scanner zelf, uit dezelfde rijen die bij elke wijziging als unit test draaien. Als de code en deze tabel uit elkaar lopen, faalt de test.
De voorbeeldentabel
Elke rij is één situatie, de controle waar het om gaat, het oordeel dat een vakman verwacht, en wat de scanner dan letterlijk zegt. De kolom Uitslag is gegenereerd door de scanner zelf, uit dezelfde rijen die de unit tests draaien.
| Situatie | Controle | Oordeel | Uitslag van de scanner |
|---|---|---|---|
| Geen enkele cookie (nulgeval) | Cookies vóór toestemming | In orde | 0 cookies gezet bij het eerste bezoek. |
| Alleen een sessiecookie PHPSESSID | Cookies vóór toestemming | In orde | 1 cookie gezet, geen van een bekend trackingproduct: PHPSESSID. Waarschijnlijk functioneel (bijvoorbeeld een sessie); controleer dat zelf in je cookieoverzicht. |
| Server zet _ga vóór toestemming | Cookies vóór toestemming | Afkeur | 1 tracking-cookie gezet zonder toestemming: _ga. |
| Google Tag Manager laadt direct | Trackers die direct laden | Advies | Bij het openen van de pagina laadt direct 1 tracker: Google Tag Manager. Zorg dat ze pas na toestemming laden, of kies een instelling die zonder toestemming mag. |
| Zelfde script, door de cookiebanner tegengehouden (type="text/plain") | Trackers die direct laden | In orde | 0 trackers gevonden die laden voordat er toestemming is. |
| Google Fonts via fonts.googleapis.com | Externe bronnen | Advies | Het IP-adres van elke bezoeker gaat naar 1 extern domein: fonts.googleapis.com. Lettertypes en scripts kun je meestal zelf hosten. |
| Plaatjes van eigen subdomein cdn. | Externe bronnen | In orde | 0 externe domeinen geladen door de homepage. |
| Geen link naar een privacyverklaring | Privacyverklaring | Advies | Geen link naar een privacyverklaring gevonden op de homepage. |
| HTTPS werkt niet: certificaat ongeldig | Versleutelde verbinding (HTTPS) | Afkeur | Geen geldige HTTPS-verbinding: het certificaat is niet geldig. |
| Zonder HTTPS-pagina: HSTS niet te meten, geen gok | HSTS | Niet gemeten | Niet gemeten: er is geen HTTPS-versie om te lezen. |
| http:// antwoordt zelf met een pagina | Doorsturen naar HTTPS | Afkeur | De onversleutelde versie antwoordt zelf (status 200) en stuurt niet door. |
| Poort 80 is dicht | Doorsturen naar HTTPS | In orde | De onversleutelde poort is dicht, dus er is geen onversleutelde versie om op te blijven. |
| http:// eerst naar http://www., dan pas https | Doorsturen naar HTTPS | Advies | Stuurt eerst door naar http://www.bakkerij-voorbeeld.nl/, en pas daarna naar HTTPS. Stuur in één stap door. |
| Certificaat nog 13 dagen geldig | Geldigheid certificaat | Advies | Geldig tot 30 oktober 2026, nog 13 dagen. Uitgegeven door Let's Encrypt. |
| Certificaat nog 14 dagen geldig (precies op de drempel) | Geldigheid certificaat | In orde | Geldig tot 31 oktober 2026, nog 14 dagen. Uitgegeven door Let's Encrypt. |
| Certificaat twee dagen geleden verlopen | Geldigheid certificaat | Afkeur | Verlopen op 15 oktober 2026. |
| HSTS ontbreekt | HSTS | Afkeur | De header Strict-Transport-Security ontbreekt. |
| HSTS max-age=0 | HSTS | Afkeur | max-age=0 zet HSTS juist uit. |
| HSTS één seconde onder een jaar | HSTS | Advies | Aanwezig, met max-age van 31.535.999 seconden (364 dagen): korter dan de drempel. |
| HSTS precies een jaar | HSTS | In orde | Aanwezig, met max-age van 31.536.000 seconden (365 dagen). |
| HSTS een uur | HSTS | Advies | Aanwezig, met max-age van 3.600 seconden (1 uur): korter dan de drempel. |
| Script via http:// op een https-pagina | Gemengde inhoud | Afkeur | 1 script, stylesheet of iframe via onversleuteld http://. |
| Plaatje via http:// op een https-pagina | Gemengde inhoud | Advies | 1 afbeelding via onversleuteld http://. |
| Geen X-Frame-Options, wel CSP frame-ancestors | Header X-Frame-Options | In orde | Geregeld via de Content-Security-Policy. |
| Referrer-Policy unsafe-url | Header Referrer-Policy | Advies | Aanwezig, maar met een waarde die niet beschermt: unsafe-url. |
| Server noemt Apache/2.4.41 | Softwareversies zichtbaar | Advies | De server noemt zijn versie: Server: Apache/2.4.41 (Ubuntu). |
| Geen WordPress | WordPress-versie | Niet van toepassing | Geen WordPress gevonden. |
| WordPress 7.1.3, de nieuwste | WordPress-versie | In orde | versie 7.1.3, de nieuwste. |
| WordPress 7.1.2: één onderhoudsupdate achter | WordPress-versie | Afkeur | versie 7.1.2 draait, de nieuwste is versie 7.1.3. Er mist een onderhouds- of beveiligingsupdate. |
| WordPress 6.8.1: een hele reeks achter | WordPress-versie | Afkeur | versie 6.8.1 draait, de nieuwste is versie 7.1.3. Deze versie loopt een hele reeks achter. |
| WordPress, versie alleen af te lezen uit ?ver= | WordPress-versie | Afkeur | versie 7.0.1 draait, de nieuwste is versie 7.1.3. Deze versie loopt een hele reeks achter. |
| WordPress met verborgen versie | WordPress-versie | Niet gemeten | Niet gemeten: dit is WordPress, maar de versie is verborgen — dat is goed, maar dan kunnen we hem niet beoordelen. |
| WordPress, maar api.wordpress.org gaf geen antwoord | WordPress-versie | Niet gemeten | WordPress versie 7.1.2 gevonden; Niet gemeten: de nieuwste versie kon niet worden opgehaald bij api.wordpress.org (geen antwoord). |
| PHP-versie niet zichtbaar | PHP-versie | Niet gemeten | Niet gemeten: de server noemt zijn PHP-versie niet — dat is goed, maar dan kunnen we hem niet beoordelen. |
| PHP/7.4.33 | PHP-versie | Afkeur | PHP versie 7.4.33: deze reeks krijgt geen beveiligingsupdates meer. |
| PHP/8.1.31 (einde op 31 december 2025) | PHP-versie | Afkeur | PHP versie 8.1.31: deze reeks krijgt geen beveiligingsupdates meer. |
| PHP/8.2.29, nog 75 dagen support | PHP-versie | Advies | PHP versie 8.2.29: beveiligingsupdates tot 31 december 2026, nog 75 dagen. |
| PHP/8.3.14 | PHP-versie | In orde | PHP versie 8.3.14: beveiligingsupdates tot 31 december 2027, nog 440 dagen. |
| PHP/8.6.0, nieuwer dan onze tabel | PHP-versie | Niet gemeten | PHP versie 8.6.0 gevonden; Niet gemeten: deze PHP-reeks staat (nog) niet in onze tabel. |
| PHP/8.3.14, maar onze tabel is over datum | PHP-versie | Niet gemeten | PHP versie 8.3.14 gevonden; Niet gemeten: onze versietabel is over haar herzieningsdatum en wordt eerst bijgewerkt. |
| Geen SPF-record | SPF | Afkeur | Geen SPF-record op bakkerij-voorbeeld.nl. |
| Twee SPF-records | SPF | Afkeur | 2 SPF-records gevonden; er mag er maar één zijn, anders telt geen enkel record. |
| SPF met +all | SPF | Afkeur | v=spf1 +all — +all staat elke server ter wereld toe om namens jou te mailen. |
| SPF met ?all | SPF | Advies | v=spf1 mx ?all — ?all zegt niets over andere servers; gebruik ~all of -all. |
| SPF met ~all | SPF | In orde | v=spf1 mx ~all |
| SPF verwijst door met redirect= | SPF | Niet gemeten | v=spf1 redirect=_spf.provider.nl; Niet gemeten: het record verwijst door naar _spf.provider.nl en dat volgen we niet. |
| DNS-opvraging voor SPF mislukt | SPF | Niet gemeten | Niet gemeten: DNS-opvraging mislukt. |
| Geen DMARC-record | DMARC | Afkeur | Geen DMARC-record op _dmarc.bakkerij-voorbeeld.nl. |
| DMARC p=none | DMARC | Advies | v=DMARC1; p=none; rua=mailto:x@y.nl — met p=none wordt vervalste mail gewoon afgeleverd. |
| DMARC p=quarantine | DMARC | In orde | v=DMARC1; p=quarantine |
| DMARC zonder p= | DMARC | Afkeur | v=DMARC1; rua=mailto:x@y.nl — het record heeft geen geldig beleid (p=). |
| Twee DMARC-records | DMARC | Afkeur | 2 DMARC-records gevonden; bij meer dan één negeert een ontvanger ze allemaal. |
| Geen lang-attribuut | Taal van de pagina | Afkeur | Geen lang-attribuut op <html>. |
| Lege titel | Paginatitel | Afkeur | De pagina heeft geen titel. |
| Geen enkele afbeelding (nulgeval) | Afbeeldingen met alt-tekst | Niet van toepassing | 0 afbeeldingen op de homepage. |
| Versierend plaatje met alt="" | Afbeeldingen met alt-tekst | In orde | Alle 1 afbeelding hebben een alt-attribuut. |
| Twee van drie plaatjes zonder alt | Afbeeldingen met alt-tekst | Afkeur | 2 afbeeldingen van de 3 afbeeldingen zonder alt-attribuut. |
| Inzoomen uitgezet met user-scalable=no | Inzoomen toegestaan | Afkeur | Inzoomen is uitgezet: width=device-width, initial-scale=1, user-scalable=no. |
| Inzoomen beperkt met maximum-scale=1 | Inzoomen toegestaan | Afkeur | Inzoomen is beperkt: width=device-width, initial-scale=1, maximum-scale=1. |
| maximum-scale=5 laat zoomen toe | Inzoomen toegestaan | In orde | Inzoomen is toegestaan. |
| Geen h1 | Hoofdkop | Advies | 0 hoofdkoppen gevonden. |
| Zoekveld met alleen een placeholder | Formuliervelden met label | Advies | 1 invulveld van de 1 invulveld zonder label. |
| Veld binnen een <label> | Formuliervelden met label | In orde | Alle 1 invulveld hebben een label. |
| Geen enkel invulveld (nulgeval) | Formuliervelden met label | Niet van toepassing | 0 invulvelden op de homepage. |
Bron: src/tests/WorkedExamples.php in de broncode van de scanner; drempels en bronnen per controle op /werkwijze/.
Lastige gevallen
Drie keuzes die je in de tabel terugziet
Nul is niet altijd goed
Een homepage zonder afbeeldingen krijgt bij alt-teksten niet van toepassing, geen in orde. Er valt niets te controleren, dus er valt ook niets goed te keuren.
Niet gemeten is geen gok
Is de WordPress-versie verborgen, of geeft api.wordpress.org geen antwoord? Dan zegt de scanner niet gemeten met de reden erbij. Die controle telt niet mee in het oordeel.
Op de drempel
Een certificaat met precies 14 dagen te gaan is in orde, met 13 dagen een advies. HSTS van precies een jaar is in orde, één seconde minder een advies. De drempels staan op de werkwijzepagina.
Vragen over de voorbeelden
Waarom is de testdatum 17 oktober 2026?
De PHP-controle rekent met datums: hoeveel dagen krijgt een PHP-reeks nog beveiligingsupdates? Met een vaste datum geeft het voorbeeld elke keer dezelfde uitkomst. Op die datum had PHP 8.2 nog 75 dagen te gaan, tot 31 december 2026, volgens php.net.
Waarom 7.1.3 als nieuwste WordPress?
Dat was de actuele versie volgens api.wordpress.org toen deze tabel werd gemaakt. De echte scan haalt de nieuwste versie bij elke scan opnieuw op, en heeft daar dus geen vaste waarde voor.
Ik vind een situatie die ontbreekt. Wat nu?
Laat het weten via de pagina Laten oplossen, met het adres van de site en wat de scanner zei. Een ontbrekend geval wordt eerst een rij in deze tabel en pas daarna een wijziging in de code.
Zie het met je eigen site
De scan is gratis, zonder account, en de uitslag staat binnen een halve minuut op je scherm.