Beveiliging afstemmen op WordPress
WordPress geeft je volledige controle over de headers en de opmaak van je pagina, dus vrijwel alles wat de controle meldt kun je zelf oplossen. Hieronder per soort bevinding waar de oplossing zit, met code die je kunt overnemen. WooCommerce is voor deze stappen gewoon WordPress: het is een plugin, dus de WordPress-oplossing voor headers geldt ook daar.
Response-headers (HSTS, clickjacking, MIME-sniffing, referrer, permissions)
HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy en Permissions-Policy zet je op één plek voor je hele site. Drie routes, kies wat bij je past. In de serverconfig is het het robuustst, want dan gelden de headers ook voor bestanden die PHP niet aanraakt.
<IfModule mod_headers.c>
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Header always set Permissions-Policy "camera=(), microphone=(), geolocation=()"
</IfModule>add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;add_action('send_headers', function () {
header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
header('X-Frame-Options: SAMEORIGIN');
header('X-Content-Type-Options: nosniff');
header('Referrer-Policy: strict-origin-when-cross-origin');
header('Permissions-Policy: camera=(), microphone=(), geolocation=()');
});Liever niet aan de code komen: een plugin
Kun je niet bij de serverconfig of functions.php, of wil je daar liever vanaf blijven, dan zet een security-headers-plugin dezelfde headers via een instellingenscherm. Voorbeelden zijn Really Simple Security en de plugin HTTP Headers; er zijn er meer. Kies er een die actief onderhouden wordt. Dit is geen aanbeveling van een specifiek product, alleen van de aanpak.
De Content-Security-Policy
De CSP is de zwaarste en de lastigste op WordPress, want thema's en plugins voegen vaak inline scripts toe die een strikte policy blokkeert. Rol hem daarom in stappen uit:
- Zet de policy eerst in report-only (de Content-Security-Policy-Report-Only-header), dan breekt hij niets maar meldt hij wel wat hij zou blokkeren.
- Verzamel de meldingen met een tool als Sentry, Report URI of URIports, of lees ze in je browserconsole.
- Sta toe wat legitiem geblokkeerd wordt, tot er geen echte meldingen meer binnenkomen.
- Hernoem de header naar Content-Security-Policy om de policy af te dwingen.
# Watch the reports first, then switch the header name to
# Content-Security-Policy once nothing legitimate is blocked.
Header always set Content-Security-Policy-Report-Only "default-src 'self'; script-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'"In de pagina (hash op een script, trackers na toestemming)
Een integrity-hash zet je op de script-tag zelf, niet in een header. In WordPress voeg je die toe via een filter op de enqueue. En trackers die pas na toestemming mogen laden, regel je met een consent-plugin of een tagmanager die op de toestemming wacht (bijvoorbeeld Complianz of CookieYes), niet door het script direct in te sluiten.
add_filter('script_loader_tag', function ($tag, $handle, $src) {
if ($handle !== 'the-external-handle') {
return $tag;
}
return str_replace(
'></script>',
' integrity="sha384-REPLACE_WITH_THE_REAL_HASH" crossorigin="anonymous"></script>',
$tag
);
}, 10, 3);De verbinding (HTTPS afdwingen)
Zet in Instellingen > Algemeen zowel het WordPress-adres als het site-adres op https, en stuur http door naar https op de server. Het certificaat zelf regelt je host of CDN voor je, vaak met een gratis Let's Encrypt-certificaat en een schakelaar.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>DNS-records (SPF, DMARC, DNSSEC, IPv6)
Deze staan los van je site: het zijn records bij je domein. Je zet ze bij je DNS-provider of domeinregistrar, niet in je CMS of op je host. SPF en DMARC gaan over wie mail namens je domein mag sturen, DNSSEC ondertekent je DNS, en IPv6 is de enige waarvoor je host eerst IPv6 moet ondersteunen voordat je het AAAA-record kunt zetten.