Hoe deze controle werkt
Scanaris ontleedt de HTML van je hoofdpagina en zoekt formulieren met een veld <input type="password">: een login, een registratie, een wachtwoordwijziging. Is er geen, dan doet hij niets. Is er wel een, dan controleert hij twee dingen. Ten eerste: is de pagina zelf over HTTP geserveerd, dan opent hij een bevinding met hoge ernst, omdat alles wat de gebruiker typt onversleuteld reist. Ten tweede: is de pagina HTTPS maar begint het action-attribuut van het formulier met http://, dan opent hij nog een bevinding met hoge ernst en die URL, omdat het versturen van het wachtwoord onversleuteld vertrekt ook al was de pagina die erom vroeg veilig. Alleen de gescande pagina wordt onderzocht; leeft je login op een andere route, scan die dan rechtstreeks.
Waarom dit belangrijk is
Een wachtwoord is het waardevolste dat een gebruiker je toevertrouwt, en het is wat onversleutelde verbindingen het slechtst behandelen. Reist een formulier over HTTP, dan kan iedereen onderweg (de wifi in een café, de internetprovider, een gecompromitteerde router) gebruikersnaam en wachtwoord zo lezen, zonder enige techniek. En omdat de meeste mensen wachtwoorden hergebruiken, lekt er meer dan alleen de toegang tot jouw site. Browsers weten dat: Chrome en Firefox markeren elk wachtwoordveld op een HTTP-pagina rood en waarschuwen de gebruiker dat het "niet veilig" is, dus naast een echt risico is het een zichtbaar verlies van vertrouwen.
Waarom het gebeurt
Het eerste geval duikt op wanneer de site HTTP niet naar HTTPS omleidt en iemand via een oude link binnenkomt. Het tweede is bijna altijd een action dat tijdens de ontwikkeling met de hand is getypt (http://localhost:3000/login of http://api.mijndomein.nl/auth) en dat niemand heeft veranderd, of een formulier dat uit een voorbeeld is gekopieerd. Het gebeurt ook wanneer de login naar een externe dienst wijst die nog geen certificaat heeft.
Hoe je het oplost
- Serveer de hele site over HTTPS en leid HTTP om. Dat is de basis van al het andere; de controle HTTPS-omleiding vertelt je of je die hebt. Op Vercel, Netlify of Cloudflare is het al gedaan; op je eigen server een omleidingsblok in nginx of Apache.
- Verander het action in een relatief pad (
action="/login"), dat het protocol van de pagina overneemt, of in de volledige URL methttps://. Gebruik je een framework (Nuxt, Next.js, Laravel, Django), dan hoort de API-URL uit een omgevingsvariabele met de productiewaarde te komen, niet in de template te staan. - Regelt een derde partij de login (Auth0, Supabase, Firebase, Clerk), dan is hun endpoint al HTTPS; de bevinding wijst dan op een eigen
actiondat daar niet hoort. - Voeg HSTS toe zodat de browser HTTP nooit meer probeert, zelfs niet bij de eerste sprong; zwakke HSTS meet dat.
Controleer of het opgelost is
curl -sI http://jouwdomein.nl/login | grep -iE "^(HTTP|location)"
curl -s https://jouwdomein.nl/login | grep -oE '<form[^>]*action="[^"]*"'
De eerste moet een 301 naar https:// teruggeven. In de tweede mag geen enkel action met http:// beginnen; normaal zie je relatieve paden of niets (formulieren zonder action versturen naar de pagina zelf).
Veelgestelde vragen
Mijn formulier verstuurt via JavaScript, niet via action. Geldt dit voor mij?
Deze controle kijkt naar het action-attribuut, dus een formulier dat een fetch doet wordt langs die weg niet gemeld. Maar het risico is hetzelfde als de fetch naar http:// wijst: op een HTTPS-pagina blokkeert de browser hem als mixed content, en op een HTTP-pagina reist hij onversleuteld. Controleer de API-URL hoe dan ook.
Het is maar een testomgeving zonder echte gebruikers.
Scan hem dan niet alsof het productie is, of accepteer de bevinding. Maar pas op met testomgevingen die in Google belanden: maakt iemand daar een account aan met zijn gebruikelijke wachtwoord, dan is het probleem echt.
Is een wachtwoordveld op een HTTPS-pagina met een relatief action in orde?
Ja. Dat is de juiste configuratie en levert geen bevinding op. Wat overblijft, is hoe je de sessie daarna bewaart: onveilige cookies en token in opslag dekken dat deel.