Hoe een site beoordeeld wordt
Het staat vast: dezelfde instellingen geven altijd dezelfde score. Hieronder staat in gewone taal hoe die tot stand komt, met onderaan de exacte gewichten per controle voor wie het wil narekenen.
- We lezen wat je site zelf verstuurt en wat een browser bij één echt bezoek ziet. We scannen niet.
- Elk punt dat eraf gaat, hoort bij iets dat we hebben gezien. Wat we niet konden meten, kost geen punten.
- We controleren je startpagina, niet wat achter een inlog of op de rest van de site staat.
- De score gaat over wat een bezoeker riskeert. Welk platform je gebruikt of hoe lastig iets op te lossen is, telt niet mee.
- Dezelfde site krijgt altijd dezelfde score, en een bewaard rapport blijft staan zoals het was.
Van bezoek tot score
- BezoekWe openen je startpagina één keer, zoals een bezoeker dat doet.
- LezenWe lezen de headers die je site meestuurt, de pagina die de browser laadt, en de publieke DNS-gegevens van je domein.
- WegenHoeveel punten een zwakte kost, hangt af van het risico voor de bezoeker. Wat we niet zagen, kost niets.
- CijferDe punten worden een letter, van A tot en met F, met het bewijs eronder.
Wat we lezen
- De HTTP-headers die je site bij elk antwoord meestuurt.
- De startpagina zoals een browser hem laadt: welke code draait, wat je site bij externe diensten ophaalt, en wat er op het apparaat van je bezoeker wordt gezet voordat er toestemming is.
- De beveiligde verbinding en het certificaat.
- De publieke DNS-gegevens van je domein, en de gegevens voor e-mail (SPF, DMARC).
Wat we niet doen
We zoeken niet naar gaten en sturen geen geprepareerde verzoeken. Dat zou de site van iemand anders aftasten in plaats van lezen. We kijken alleen naar je startpagina, niet achter een inlog of op de rest van de site. We beoordelen de instellingen die je site meestuurt, niet de software erachter: of je platform en uitbreidingen up-to-date zijn valt buiten deze score. En we bewaren niet wie een controle deed.
Hoe de score tot stand komt
Honderd punten, min wat er mis is
Elke site begint op 100. Hoeveel punten een zwakte kost hangt af van het risico, en een paar goede praktijken geven er een paar terug. Het getal wordt begrensd op 0 en 100 en vertaald naar een letter, A tot en met F.
Eén regel bepaalt elk gewicht
Wat een zwakte kost hangt af van of dit risico al ergens door beschermd wordt, wat een aanvaller ermee wint, en hoe ver de zwakte op eigen kracht reikt. Geen enkel gewicht is op gevoel gekozen, en hieronder staat het antwoord voor elke controle.
De score spreekt voor de bezoeker
De score weegt wat een bezoeker riskeert, niet hoe makkelijk jij het kunt oplossen. Een site op een gesloten platform dat geen header kan zetten is net zo kwetsbaar als een site die het wel kon en het niet deed. Voor de bezoeker maakt dat verschil niet uit, dus voor de score ook niet. Het advies eronder houdt wel rekening met waar je zit: bij elk oordeel noemen we waar een oplossing kan liggen, van je applicatie tot je hostingprovider, vaak meer dan één plek.
Een bewaard rapport verandert niet
Dezelfde site krijgt altijd dezelfde score. Bewaar je een rapport, dan blijft het staan zoals het was, ook als we het model later aanpassen: het is gedateerd bewijs, geen momentopname die met ons meebeweegt. Deel je de link, dan blijf je laten zien wat je zag. Het enige wat we bij het openen doen, is het rapport zo nodig vertalen.
Van punten naar een letter
Het eindgetal, van 0 tot 100, valt in een van zes banden. Hieronder zie je welk getal bij welke letter hoort.
- A: 90-100
- B: 80-89
- C: 65-79
- D: 50-64
- E: 35-49
- F: 0-34
Alle controles en hun gewicht, om na te rekenen
Alle controles en hun gewicht, om na te rekenen
Eén keer wegen, niet per symptoom
Ontbreekt de basisbescherming voor een risico, dan kost dat het volledige gewicht ervan, en komen de kleinere controles daar niet meer bovenop. Zo'n controle blijft wel in het rapport staan met zijn advies, want zodra de basis er is gaat hij weer meetellen. Is de basis in orde, dan tellen de losse controles gewoon bij elkaar op. We beoordelen de opzet van een policy, niet de diensten die hij noemt.
Een ernstige fout begrenst de score
Sommige oordelen leggen een plafond op de score, hoeveel punten er verder ook staan, omdat de rest van de punten zo'n fout niet kan goedmaken. Een site die losse code in de pagina toestaat, of die over een onbeveiligde verbinding (http) antwoordt, houdt de score laag hoe goed de rest ook is.
Geen policy telt als de slechtste policy
Helemaal geen policy sturen is niet neutraal. Het laat je pagina net zo onbeschermd als een policy die alles toestaat, dus het telt ook zo mee. Wat dat kost rekenen we uit door zo'n alles-toestaan-policy langs precies dezelfde controles te leggen. Daardoor kunnen we je nooit vertellen dat het weghalen van een beveiligingsinstelling je score verbetert.
Niet getest telt nooit als fout
Een controle die vastliep of niet kon draaien staat er als niet getest, nul punten, met de reden. Zo'n controle zegt niets over de site, en hem als een rood kruis rapporteren zou een uitkomst verzinnen. Zolang er iets niet gemeten kon worden mag de score ook niet bovenin de schaal komen, want een ongemeten gat als in orde tellen is net zo goed een uitkomst verzinnen.
En hier staat wat elke controle kost. Gegenereerd uit het model zelf, zodat deze pagina geen schaal kan beschrijven die we niet meer gebruiken. Punten gaan van honderd af, en een risico kan nooit meer kosten dan zijn plafond, hoeveel oordelen er ook in zitten.
Cross-site scripting (XSS)
kost hoogstens 30 puntenKrijgt iemand hier eigen script aan het draaien, dan is alles op de pagina van hem: wat er getypt wordt, wat er getoond wordt, en waar het formulier heen gaat.
- -30Hier is niets beschermd. Dat kost het volledige gewicht van dit risico, en daar komt niets meer bovenop.
- 1Content-Security-Policy wordt niet afgedwongen
- 2script-src (en default-src) ontbrekenhoogstens C
- 3script-src staat elke host toehoogstens C
- 4data: in script-srchoogstens C
- 5'unsafe-inline' in script-srchoogstens C
- -10Een aanvaller kan dit op zichzelf al misbruiken. Er hoeft verder niets mis te zijn.
- 6base-uri ontbreekt
- 7blob: in script-src
- 8Gedeeld platform in script-src
- 9Een nonce of hash mist z'n aanhalingstekens en doet daardoor niets
- 10'unsafe-eval' in script-srchoogstens B
- -5Dit werkt pas als er nog iets anders mis is, maar dan raakt het wel iedereen die de pagina opent.
- 11base-uri is aanwezig maar zwak
- 12default-src ontbreekt
- 13Te brede bronnen in andere fetch-directives2 punten per te ruime directive, hoogstens 5
- 14form-action ontbreekt
- 15style-src staat te brede bronnen toe
- 16CSP-sleutelwoord zonder aanhalingstekens
- 17Externe scripts komen binnen zonder hash
- 18X-Content-Type-Options ontbreekt of is niet 'nosniff'
- -2Dit is op zichzelf niet te misbruiken. Het maakt een aanval makkelijker of stelt je bezoeker bloot aan een andere dienst.
- 19object-src is niet afgedekt
- 20object-src is niet 'none'
- 21'unsafe-inline' in style-src
- +3Dit gaat verder dan wat gebruikelijk is. Het levert punten op in plaats van dat het punten kost.
- 34CSP-rapportage staat aan
- 35Trusted Types zijn verplicht voor script
Veilige verbinding (https)
kost hoogstens 35 puntenWie tussen je bezoeker en je server zit, kan meelezen of veranderen wat er langskomt. Dit is het enige risico waarvoor verder niets mis hoeft te zijn.
- -35Hier is niets beschermd. Dat kost het volledige gewicht van dit risico, en daar komt niets meer bovenop.
- 36Gewone http wordt niet omgeleid naar httpshoogstens D
- 37TLS ontbreekt op deze URLhoogstens F
- 38Het certificaat is verlopenhoogstens D
- 39Het certificaat is niet geldig voor deze hostnaamhoogstens D
- 40De certificaatketen valideert niethoogstens D
- -10Een aanvaller kan dit op zichzelf al misbruiken. Er hoeft verder niets mis te zijn.
- 41Strict-Transport-Security (HSTS) ontbreekt
- 42Strict-Transport-Security heeft geen max-age
- 43De pagina laadt onderdelen over http
- 44Er laden onveilige bronnen bij het openen van de pagina
- 45Verouderde TLS-versiehoogstens D
- -5Dit werkt pas als er nog iets anders mis is, maar dan raakt het wel iedereen die de pagina opent.
- 46Cookies worden zonder Secure-vlag gezet
- 47Een ingelogde sessie is leesbaar door JavaScript
- 48Strict-Transport-Security max-age is korter dan een jaar
- -2Dit is op zichzelf niet te misbruiken. Het maakt een aanval makkelijker of stelt je bezoeker bloot aan een andere dienst.
- 49Cookies gaan mee met verzoeken vanaf andere sites
- 50Bescherming tegen mixed content ontbreekt
- 51Strict-Transport-Security zonder includeSubDomains
Ingesloten in een frame (clickjacking)
kost hoogstens 10 puntenJe pagina kan onzichtbaar in die van iemand anders geladen worden, zodat een bezoeker op iets anders klikt dan hij ziet.
- -10Hier is niets beschermd. Dat kost het volledige gewicht van dit risico, en daar komt niets meer bovenop.
- 61Bescherming tegen clickjacking ontbreekt
- 62X-Frame-Options heeft een ongeldige waarde
Externe diensten
kost hoogstens 10 puntenWelke externe diensten code laten draaien of gegevens ontvangen zodra iemand je pagina opent, en onder welk recht die diensten vallen.
- -2Dit is op zichzelf niet te misbruiken. Het maakt een aanval makkelijker of stelt je bezoeker bloot aan een andere dienst.
- 68Permissions-Policy ontbreekt
- 69Referrer-Policy ontbreekt
- 70Referrer-Policy is zwak
Privacy
kost hoogstens 10 puntenWat er draait en wat er wordt opgeslagen voordat er ja op gezegd is, en onder welk recht de gegevens vallen die je pagina naar buiten stuurt. Of dat mag hangt af van waar het voor dient, en dat is van buitenaf niet te zien.
- -10Hier is niets beschermd. Dat kost het volledige gewicht van dit risico, en daar komt niets meer bovenop.
- 79Er stond al iets op het apparaat van je bezoeker voordat er toestemming was
Domein en DNS
kost hoogstens 12 puntenOf bezoekers je server überhaupt bereiken, en of het werkelijk de jouwe is waar ze uitkomen.
- -10Een aanvaller kan dit op zichzelf al misbruiken. Er hoeft verder niets mis te zijn.
- 87DNSSEC is ondertekend maar kapot
- -5Dit werkt pas als er nog iets anders mis is, maar dan raakt het wel iedereen die de pagina opent.
- 88DNSSEC staat niet aan op het domein
- 89Niet bereikbaar over IPv6
Of iemand anders mail kan sturen die van jouw domein lijkt te komen. De gedupeerde is hier een ontvanger, niet een bezoeker.
- -2Dit is op zichzelf niet te misbruiken. Het maakt een aanval makkelijker of stelt je bezoeker bloot aan een andere dienst.
- 98DMARC-record heeft geen bruikbare policy
- 99Geen DMARC-record
- 100DMARC staat alleen op meekijken (p=none)
- 101Geen SPF-record
- 102SPF staat elke server toe om te versturen (+all)
Melden en zichtbare software-info
kost geen puntenOf iemand die een fout vindt weet waar hij het kwijt kan, en wat je response-headers en je pagina prijsgeven over de software die je draait.
- +2Dit gaat verder dan wat gebruikelijk is. Het levert punten op in plaats van dat het punten kost.
- 112security.txt is gepubliceerd en actueel
Toegankelijkheidsverklaring
kost geen puntenEen toegankelijkheidsverklaring, in het officiële register en op de pagina zelf. We stellen niet vast of die verplichting voor jou geldt.
Wat we hier vinden staat in het rapport als waarneming. Het kost geen punten, omdat we van buitenaf niet kunnen vaststellen of het fout is.
Niet gemeten
kost geen puntenControles die niet konden draaien. Niets hiervan is een oordeel over je site.
Deze controles konden niet draaien. Ze staan in het rapport als niet getest, zonder punten.
Zo los je het op
Concreet advies per platform, met code die je kunt overnemen: