HTTP-responsheaders vertellen de browser hoe hij met uw pagina’s moet omgaan: welke scripts mogen draaien, of de site in een frame mag worden geladen, en of hij altijd via HTTPS moet laden. Een handvol headers blokkeert hele categorieën aanvallen tegen vrijwel geen kosten. Andere zijn verouderd en voegen alleen ruis toe, of zelfs risico.
Een basis om mee te beginnen
Dit is een redelijk vertrekpunt voor een HTML-applicatie die alleen via HTTPS wordt aangeboden. Plak het niet ongewijzigd over. Vooral de CSP moet aansluiten bij de manier waarop uw pagina’s scripts laden, de nonce moet voor elk antwoord nieuw zijn, en HSTS-preload is lastig terug te draaien.
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
Content-Security-Policy: script-src 'nonce-3f9a1c7e2b' 'strict-dynamic'; object-src 'none'; base-uri 'none'; frame-ancestors 'none'
X-Content-Type-Options: nosniff
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), camera=(), microphone=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-site
Content-Security-Policy
CSP beperkt waarvandaan scripts en andere bronnen mogen komen. De belangrijkste taak is cross-site scripting (XSS) veel moeilijker te misbruiken te maken.
Het OWASP-cheatsheet voor CSP geeft de voorkeur aan een strikt beleid op basis van nonces of hashes boven een lange lijst toegestane domeinen. Allowlists die te ruim of te gedetailleerd zijn, worden vaak omzeild. Een beleid op basis van nonces ziet er zo uit:
Content-Security-Policy: script-src 'nonce-3f9a1c7e2b' 'strict-dynamic'; object-src 'none'; base-uri 'none'
Elke scripttag krijgt dan dezelfde waarde mee, zoals in <script nonce="3f9a1c7e2b">. De nonce moet willekeurig zijn en voor elk antwoord nieuw; een vaste waarde maakt het hele mechanisme zinloos. Genereer de nonce in uw templatelaag. OWASP waarschuwt voor middleware die de nonce aan elke scripttag toevoegt, omdat die dan ook geïnjecteerde scripts goedkeurt.
Zijn uw pagina’s statisch, gebruik dan hashes: 'sha256-...'-waarden voor elk inline script. Elke wijziging in het script, zelfs in witruimte, verandert de hash.
Vermijd 'unsafe-inline' en 'unsafe-eval' in script-src. Die zetten precies open wat CSP moet dichthouden.
Om in te voeren zonder iets te breken, stuurt u het beleid eerst als Content-Security-Policy-Report-Only. Browsers melden dan overtredingen zonder iets te blokkeren. Los op wat de meldingen laten zien en schakel daarna over op handhaving.
Trusted Types
Trusted Types zijn gericht op DOM-gebaseerde XSS, waarbij uw eigen JavaScript strings die een aanvaller beheert doorgeeft aan gevaarlijke API’s zoals innerHTML, eval() of de src van een scriptelement. U schakelt ze in met CSP:
Content-Security-Policy: require-trusted-types-for 'script'; trusted-types app-policy
Met handhaving aan geeft het doorgeven van een gewone string aan een van deze sinks een foutmelding. Code moet waarden doorgeven die door een benoemd beleid zijn gemaakt, meestal een beleid dat HTML opschoont. MDN vermeldt de API sinds februari 2026 als Baseline, wat betekent dat hij werkt in de actuele versies van de grote browsers. Begin in report-only-modus, omdat bestaande code mogelijk strings rechtstreeks in de DOM schrijft.
Strict-Transport-Security en preload
HSTS vertelt browsers dat ze alleen via HTTPS verbinding mogen maken met uw domein, gedurende het aantal seconden in max-age. Met includeSubDomains geldt de regel ook voor elk subdomein.
De preloadlijst gaat verder. Browsers hebben de lijst ingebouwd, dus zelfs het eerste bezoek aan uw domein gebruikt HTTPS. De eisen op hstspreload.org zijn:
- een geldig certificaat, en een doorverwijzing van HTTP naar HTTPS op dezelfde host
- elk subdomein via HTTPS aangeboden, ook interne subdomeinen
- een
max-agevan minstens 31536000 (één jaar), plusincludeSubDomainsenpreload - de HSTS-header ook op doorverwijzingen vanaf de HTTPS-site
Voer dit in stappen in. De preloadsite stelt voor te beginnen met max-age=300, dan één week (604800), dan één maand (2592000), en bij elke stap te letten op wat er misgaat. Verwijdering van de preloadlijst duurt maanden voordat die bij gebruikers aankomt, dus zorg dat elk subdomein HTTPS op de lange termijn kan ondersteunen.
X-Content-Type-Options
X-Content-Type-Options: nosniff voorkomt dat browsers het type van een bestand raden aan de hand van de inhoud. Combineer het met een correct Content-Type op elk antwoord, inclusief een charset voor HTML, zoals text/html; charset=UTF-8.
frame-ancestors en X-Frame-Options
Clickjacking werkt door uw pagina onzichtbaar in een frame op een andere site te laden. De CSP-directive frame-ancestors bepaalt wie u in een frame mag laden, en OWASP merkt op dat die X-Frame-Options vervangt in browsers die haar ondersteunen.
Twee details zetten mensen vaak op het verkeerde been. Volgens MDN valt frame-ancestors niet terug op default-src, dus u moet de directive expliciet instellen. Ze werkt ook niet in een <meta>-tag, alleen als header. Voor oudere browsers kan het geen kwaad om beide te sturen:
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
Gebruik frame-ancestors 'self' als uw eigen site haar pagina’s in frames laadt. Vermijd X-Frame-Options: ALLOW-FROM; dat is verouderd. MDN merkt op dat moderne browsers de hele header negeren als ze die waarde zien.
Referrer-Policy
Deze header bepaalt hoeveel van de huidige URL in de header Referer naar andere sites wordt gestuurd. Stelt u niets in, dan gebruiken browsers standaard strict-origin-when-cross-origin, waarbij via HTTPS alleen de origin naar andere sites gaat. OWASP raadt toch aan de header expliciet in te stellen. Gebruik no-referrer of same-origin als uw URL’s tokens of persoonsgegevens kunnen bevatten.
Permissions-Policy
Permissions-Policy schakelt browserfuncties uit die uw site niet gebruikt. Een lege allowlist, (), schakelt een functie uit voor uw pagina en voor elk frame daarin:
Permissions-Policy: geolocation=(), camera=(), microphone=(), payment=()
Is een functie nodig, sta die dan beperkt toe, bijvoorbeeld camera=(self).
COOP en CORP
Cross-Origin-Opener-Policy: same-origin plaatst uw pagina in een eigen groep browsercontexten. Een pagina die de uwe opent met window.open(), kan dan geen verwijzing ernaar vasthouden, en daarmee is een categorie cross-site-lekaanvallen (XS-Leaks) afgesloten. Gebruikt u pop-ups voor single sign-on of betalingen, dan blijven die werken met same-origin-allow-popups.
Cross-Origin-Resource-Policy: same-site voorkomt dat andere sites uw bronnen, zoals afbeeldingen of scripts, insluiten. Cross-Origin-Embedder-Policy: require-corp is alleen nodig voor cross-origin-isolatie, die functies als SharedArrayBuffer vereisen. Laat COEP weg tenzij u die functies nodig hebt, want het blokkeert cross-origin-bronnen die zich er niet expliciet voor openstellen.
Headers die u kunt schrappen
| Header | Status | Wat u doet |
|---|---|---|
X-XSS-Protection | Afgeschaft en niet-standaard; MDN waarschuwt dat de header XSS-lekken kan veroorzaken in sites die anders veilig zijn | Verwijder hem, of stuur 0, en vertrouw op CSP |
Expect-CT | Afgeschaft | Verwijder hem |
Public-Key-Pins | In 2018 uit Chromium verwijderd | Verwijder hem; gebruik in plaats daarvan Certificate Transparency en CAA-records |
X-Frame-Options: ALLOW-FROM | Verouderd | Gebruik frame-ancestors |
Server, X-Powered-By | Verraden software en versies | Verwijder ze of gebruik een neutrale waarde |
Waar u begint
- Controleer met onze scanner voor beveiligingsheaders wat uw site vandaag verstuurt.
- Voeg eerst de headers met weinig risico toe:
X-Content-Type-Options,Referrer-Policy,Permissions-Policyenframe-ancestors. - Voer HSTS in met een korte
max-ageen verhoog die in stappen. Overweeg preload pas als elk subdomein er klaar voor is. - Draai CSP een paar weken in report-only-modus, los de overtredingen op en ga daarna handhaven.
Bouwt u een nieuwe applicatie en wilt u dat dit vanaf het begin goed wordt ontworpen? Ons team voor veilige software helpt u graag.
