Oplossingsgids

HTTP security headers instellen via .htaccess vs Nginx

20 mei 2026

HTTP security headers zijn response headers die browsers vertellen om specifieke beveiligingsgedragingen af te dwingen bij het renderen van een pagina. Ze worden geconfigureerd op de webserver, niet in WordPress, en kosten geen performance bij het activeren. Een WordPress-site met correcte headers blokkeert clickjacking, downgrades naar gemixte content, MIME-sniffing-exploits en een groot deel van cross-site scripting-payloads. De setup is een eenmalige wijziging in ofwel Apaches .htaccess of in de Nginx-server-config. Hieronder staan de zeven headers die in 2026 tellen, met kopieer-plak snippets voor beide webservers.

Welke HTTP security headers moet een WordPress-site instellen?

Zeven headers dekken het realistische dreigingsmodel voor een content-gedreven site. Op prioriteit:

  • Strict-Transport-Security (HSTS). Dwingt browsers om HTTPS te gebruiken gedurende een jaar (of langer) na het eerste bezoek, en voorkomt HTTPS-stripping-aanvallen op openbaar WiFi. Verplicht als je site ingelogde gebruikers heeft.
  • Content-Security-Policy (CSP). Vertelt browsers precies welke bronnen van JavaScript, CSS, afbeeldingen en fonts zijn toegestaan. De meest impactvolle header tegen XSS, maar ook de lastigste om te configureren zonder je site te breken.
  • X-Frame-Options of de CSP-directive frame-ancestors. Voorkomt dat je site in een iframe op een ander domein wordt ingebed, waarmee clickjacking-aanvallen tegen het loginformulier worden geblokkeerd.
  • X-Content-Type-Options: nosniff. Stopt browsers van het raden van het content-type van een response, wat een klasse van "upload een nep-afbeelding die eigenlijk JavaScript is"-aanvallen sluit.
  • Referrer-Policy. Bepaalt hoeveel van de huidige URL wordt verzonden in de Referer-header bij uitgaande klikken. Defaults lekken query strings naar derden; strict-origin-when-cross-origin is de moderne aanbeveling.
  • Permissions-Policy (voorheen Feature-Policy). Schakelt browserfuncties uit die je site niet gebruikt (camera, microfoon, geolocatie), wat blootstelling vermindert als een third-party script ooit probeert ze te benaderen.
  • Cross-Origin-Opener-Policy. Isoleert je site van popup-vensters die het opent, en mitigeert Spectre-klasse side-channel-aanvallen. Vereist voor SharedArrayBuffer om te werken.

Wat niet meer wordt aanbevolen: X-XSS-Protection (deprecated, browsers negeren het), Public-Key-Pins (deprecated, veroorzaakte te veel lockouts) en Expect-CT (deprecated sinds 2023).

Apache .htaccess: kopieer-plak security header block

Voeg dit toe aan de bovenkant van je WordPress-root .htaccess, boven het WordPress-block (# BEGIN WordPress). De IfModule-guard zorgt ervoor dat het snippet niet crasht als mod_headers ontbreekt.

<IfModule mod_headers.c>
    # HSTS: dwing HTTPS af voor 1 jaar, inclusief subdomeinen, preload-ready
    Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"

    # Voorkom clickjacking
    Header always set X-Frame-Options "SAMEORIGIN"

    # Blokkeer MIME-sniffing
    Header always set X-Content-Type-Options "nosniff"

    # Beperk referrer-lekkage
    Header always set Referrer-Policy "strict-origin-when-cross-origin"

    # Schakel ongebruikte browserfuncties uit
    Header always set Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()"

    # Cross-origin isolatie
    Header always set Cross-Origin-Opener-Policy "same-origin"

    # Conservatieve start-CSP; aanscherpen zodra je weet wat je site laadt
    Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';"
</IfModule>

Het sleutelwoord always is kritisch. Zonder dit worden headers alleen verzonden bij 2xx- en 3xx-responses; met dit dragen ook foutpagina's en redirects de headers. Zonder always ziet een aanvaller die een 500-fout veroorzaakt een onbeveiligde response.

De mod_headers-module moet ingeschakeld zijn. Op shared hosting is dat meestal al het geval. Op een zelfbeheerde Apache: sudo a2enmod headers && sudo systemctl reload apache2.

Nginx: kopieer-plak security header block

Voeg dit toe binnen het server { ... }-block van je site, doorgaans in /etc/nginx/sites-available/jouwsite.conf:

    # HSTS: dwing HTTPS af voor 1 jaar, inclusief subdomeinen, preload-ready
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;

    # Voorkom clickjacking
    add_header X-Frame-Options "SAMEORIGIN" always;

    # Blokkeer MIME-sniffing
    add_header X-Content-Type-Options "nosniff" always;

    # Beperk referrer-lekkage
    add_header Referrer-Policy "strict-origin-when-cross-origin" always;

    # Schakel ongebruikte browserfuncties uit
    add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always;

    # Cross-origin isolatie
    add_header Cross-Origin-Opener-Policy "same-origin" always;

    # Conservatieve start-CSP; aanscherpen zodra je weet wat je site laadt
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https:; style-src 'self' 'unsafe-inline' https:; img-src 'self' data: https:; font-src 'self' data: https:; connect-src 'self' https:; frame-ancestors 'self'; base-uri 'self'; form-action 'self';" always;

De afsluitende always in Nginx dient hetzelfde doel als in Apache: het maakt dat de header ook van toepassing is op foutresponses. Herlaad Nginx na de wijziging: sudo nginx -t && sudo systemctl reload nginx.

De twee-valstrikken regel van Nginx add_header

Nginx heeft een eigenaardigheid die mensen herhaaldelijk bijt. Twee regels om te internaliseren voordat je productie-config aanraakt:

  • add_header wordt vervangen, niet samengevoegd. Als je headers instelt in het server-block en opnieuw in een location-block, vervangen de location-block-headers de server-block-headers voor die location. Ze worden niet eraan toegevoegd. Het symptoom: headers werken overal behalve binnen een specifieke location (zoals /wp-admin/ waar je een custom regel toevoegde).
  • Voeg altijd de always-vlag toe. Zonder dat wordt een 404-pagina of een 500-foutpagina geserveerd zonder je security headers. Aanvallers kunnen opzettelijk fouten veroorzaken om header-gebaseerde beschermingen te omzeilen.

Apaches Header always set is het equivalent van Nginx' always-vlag en heeft hetzelfde effect.

Apache vs Nginx: welke is makkelijker te configureren?

Praktisch equivalent voor security headers. Beide gebruiken een enkele directive per header en accepteren identieke header-waarden. Drie verschillen die de moeite waard zijn om te weten:

  • Waar de config woont. Apache via .htaccess kan per directory bewerkt worden door iedereen met FTP-toegang tot de WordPress-installatie. Nginx-config woont buiten de document root en vereist meestal SSH plus een reload. Voor shared WordPress-hosting is .htaccess praktischer; voor managed Nginx-setups is de server-config meer performant (Nginx leest .htaccess-equivalente regels niet bij elk verzoek opnieuw, maar de juiste nginx-config wordt in geheugen gehouden).
  • Per-location overrides. Apache .htaccess erft automatisch de instellingen van de parent directory. Nginx location-blocks hebben expliciete her-declaratie nodig als je er een aanpast (vanwege de merge-valstrik hierboven).
  • Hosting-realiteit. De meeste shared WordPress-hosting (Hostinger, IONOS, GoDaddy, traditionele cPanel-hosts) is Apache. De meeste managed WordPress-hosting (Kinsta, WP Engine, Raidboxes, SiteGround, Cloudways) is Nginx. De marktverdeling is in de afgelopen vijf jaar verschoven van Apache-meerderheid naar ruwweg 50/50.

Moet ik security headers in WordPress toevoegen in plaats van op de webserver?

Kan, maar webserver-niveau is beter. Drie WordPress-zijde opties bestaan:

  • Security plugin (Wordfence, iThemes Security, enz.). Heeft een "security headers"-functie die dezelfde headers PHP-zijde toevoegt. Werkt maar voegt een paar milliseconden per verzoek toe. Nuttig als je geen webserver-toegang hebt.
  • Custom plugin- of theme-code. Een kleine mu-plugin kan header() in PHP aanroepen om elke header uit te sturen. Zelfde overhead, zelfde voorbehouden.
  • Webserver-config (aanbevolen). Nul PHP-overhead, geldt voor elke response inclusief 404-fouten en statische bestanden, overleeft WordPress-crashes.

Het argument voor webserver-niveau: in PHP toegevoegde headers beschermen geen responses die PHP omzeilen. Als een aanvaller een statisch bestand direct bereikt (een overgebleven .phps-backup, een uploadmap met HTML-bestanden), worden door PHP gezette headers niet toegepast. De webserver ziet elk verzoek en is de juiste laag.

Hoe stem ik de Content-Security-Policy af zonder mijn site te breken?

CSP is de meest impactvolle security header en ook de meest waarschijnlijke om dingen te breken. Een WordPress-site laadt standaard scripts en stijlen van tientallen bronnen: jQuery uit /wp-includes, theme-assets, plugin-assets, Google Fonts (als niet zelf gehost), analytics, ingesloten YouTube, enz. Een strikte CSP die deze niet expliciet whitelist, zal ze blokkeren en de site lijkt op subtiele manieren gebroken (login mislukt, galerij werkt niet, analytics stopt).

Het twee-fasen uitrolpatroon dat werkt:

  1. Begin in report-only modus. Gebruik Content-Security-Policy-Report-Only in plaats van Content-Security-Policy. De browser blokkeert niets; hij logt overtredingen alleen in de developer console. Browse je site een paar dagen, monitor wat zou zijn geblokkeerd, en voeg de legitieme bronnen toe aan je beleid.
  2. Schakel naar enforcing-modus. Zodra de report-only modus nul overtredingen toont bij normaal browsen, verander de header-naam terug naar Content-Security-Policy. Nu worden overtredingen geblokkeerd.

Een veelvoorkomende valkuil: WordPress en veel plugins gebruiken inline JavaScript event handlers (onclick="") en inline <script>-blocks. Een strikte CSP vereist ofwel 'unsafe-inline' (verslaat het grootste deel van de bescherming) of nonces voor elk inline script (significante code-wijzigingen). De pragmatische middenweg in 2026: houd 'unsafe-inline' voorlopig, maar vergrendel de andere directives. Toekomstige WordPress-versies bewegen richting nonce-vriendelijke inline scripts.

Hoe verifieer ik dat mijn security headers werken?

Vier methoden, van snelste naar meest gezaghebbend:

  1. InspectWP-rapport. De Security-sectie lijst elke header die je site instelt, de waarde, en markeert ontbrekende of slecht geconfigureerde. Eén scherm.
  2. curl vanaf de commandline. curl -I https://jouwsite.com drukt de response headers af. Zoek naar de zeven headers hierboven; verifieer hun waarden.
  3. securityheaders.com. Een gratis publieke scanner die je site beoordeelt (A+ tot F) en uitlegt welke headers ontbreken of zwak zijn. Industriestandaard voor header-audits.
  4. Browser DevTools. Open DevTools (F12), Network-tab, klik op het document-verzoek, kijk in de Response Headers-sectie. Nuttig om CSP-overtredingen live te zien in de Console-tab.

Veelvoorkomende fouten en valkuilen

  • HSTS toevoegen zonder te bevestigen dat HTTPS site-breed werkt. HSTS dwingt browsers om HTTPS te gebruiken gedurende een jaar. Als je site een kapot certificaat of een subpagina heeft die alleen over HTTP werkt, worden gebruikers buitengesloten. Test HTTPS grondig voordat je HSTS inschakelt. Begin met een korte max-age (zoals 300 seconden) en bouw op naar een jaar.
  • X-Frame-Options EN CSP frame-ancestors instellen. Beide werken maar frame-ancestors is het moderne equivalent. Beide instellen is overbodig maar onschadelijk; moderne browsers prefereren frame-ancestors.
  • includeSubDomains vergeten in HSTS. Als je hoofdsite HTTPS is maar een subdomein nog HTTP serveert, kunnen aanvallers via het subdomein pivoten. includeSubDomains dwingt HTTPS overal onder je domein af. Verifieer dat alle subdomeinen HTTPS zijn voordat je dit toevoegt.
  • Een CSP kopiëren uit een generieke tutorial. Elke WordPress-site laadt verschillende third-party assets. Een generieke CSP zal je site breken. Gebruik eerst report-only modus.
  • CDN- en origin-headers mengen. Als je Cloudflare ervoor hebt, kun je headers bij Cloudflare instellen (Page Rules of Transform Rules) of bij de origin. Beide instellen met verschillende waarden veroorzaakt verwarring bij debuggen. Kies één plek en documenteer het.
  • Herladen vergeten na bewerking. Nginx-wijzigingen doen niets totdat systemctl reload nginx. Apache .htaccess-wijzigingen zijn direct; Apache main config-wijzigingen vereisen een reload.

Hoe zit het met HTTP/3 en het moderne header-verhaal?

HTTP/3 verandert niets over welke headers in te stellen; de header-semantiek is identiek over HTTP/1.1, HTTP/2 en HTTP/3. Eén header die relevant wordt op HTTP/3 is Alt-Svc, die HTTP/3-beschikbaarheid adverteert aan clients die via HTTP/2 aankwamen. De meeste webservers voegen dit automatisch toe.

Het browserlandschap beweegt ook geleidelijk naar het afdwingen van moderne defaults zelfs wanneer headers ontbreken. Chrome en Firefox defaulten nu naar strict-origin-when-cross-origin voor Referrer-Policy als geen header wordt verzonden, en nemen steeds vaker HTTPS aan voor elke site die ooit over HTTPS is geserveerd. De headers expliciet instellen wordt nog steeds aanbevolen omdat de defaults variëren per browserversie en omdat niet-browser HTTP-clients (curl, scripts, monitoringtools) deze defaults niet implementeren.

Wat InspectWP controleert

De Security-sectie van elk InspectWP-rapport inspecteert de response-headers van je hoofddocument en rapporteert welke van de standaard security headers aanwezig zijn, wat hun waarden zijn, en welke ontbreken of op niet-aanbevolen waarden zijn ingesteld. Ontbrekend HSTS op een HTTPS-site wordt als waarschuwing gemarkeerd; ontbrekend X-Content-Type-Options wordt als informatief gemarkeerd; een CSP ingesteld op default-src * (effectief geen policy) wordt als misconfiguratie gemarkeerd. Het rapport noteert ook wanneer headers op CDN-niveau versus origin-niveau worden ingesteld, omdat dat beïnvloedt wat je zou moeten veranderen om ze bij te werken. De aanbevolen staat is alle zeven headers aanwezig met redelijke waarden, en CSP ofwel in report-only modus terwijl je hem afstemt of in enforcing-modus zodra afgestemd.

Controleer nu uw WordPress-site

InspectWP analyseert uw WordPress-site op beveiligingsproblemen, SEO-problemen, GDPR-naleving en prestaties — gratis.

Analyseer uw site gratis