Elke dag worden duizenden WordPress-sites gehackt. Niet omdat WordPress inherent onveilig is, maar omdat beheerders de basis van security hardening overslaan. Een standaard WordPress-installatie is ontworpen voor gebruiksgemak, niet voor maximale beveiliging. Dat betekent dat er na installatie werk aan de winkel is.
In deze serie hebben we uitgebreid stilgestaan bij performance-optimalisatie en server-tuning. Maar een snelle site die gehackt wordt, heb je niets aan. Security is geen luxe - het is een voorwaarde. In dit artikel leer je stap voor stap hoe je jouw WordPress-installatie verhardt tegen de meest voorkomende aanvallen.
Waarom standaard WordPress niet genoeg is
Na een verse installatie staat WordPress in een configuratie die gericht is op compatibiliteit. Bestandsrechten zijn ruim, de login-pagina is voor iedereen bereikbaar, XML-RPC staat open, en versie-informatie is zichtbaar in de broncode. Aanvallers weten dit en scannen geautomatiseerd op precies deze zwakke plekken.
De drie meest voorkomende aanvalsvectoren:
- Brute-force aanvallen op wp-login.php - geautomatiseerde bots die duizenden wachtwoordcombinaties proberen
- Exploits in verouderde plugins en thema's - bekende kwetsbaarheden die publiek gedocumenteerd zijn
- Onbeveiligde serverbestanden - toegang tot wp-config.php, .htaccess of debug-logs
Hardening betekent dat je deze aanvalsoppervlakken systematisch verkleint. Niet met één magische plugin, maar met een gelaagde aanpak.
Bestandsrechten en eigenaarschap
De eerste stap is simpel maar cruciaal: zorg dat bestands- en maprechten correct staan. Verkeerde permissions zijn een open uitnodiging.
Aanbevolen rechten
| Pad | Rechten | Uitleg |
|---|---|---|
| Mappen | 755 |
Leesbaar en uitvoerbaar voor iedereen, schrijfbaar alleen voor eigenaar |
| Bestanden | 644 |
Leesbaar voor iedereen, schrijfbaar alleen voor eigenaar |
wp-config.php |
440 of 400 |
Alleen leesbaar door eigenaar en groep, niet schrijfbaar |
.htaccess |
644 |
Leesbaar, schrijfbaar door eigenaar |
Controleer het eigenaarschap met ls -la in je WordPress-root. De bestanden moeten eigendom zijn van je webserver-gebruiker (vaak www-data of nginx), niet van root.
# Rechten in één keer corrigeren
find /var/www/html -type d -exec chmod 755 {} \;
find /var/www/html -type f -exec chmod 644 {} \;
chmod 440 /var/www/html/wp-config.php
wp-config.php verplaatsen
Weinig mensen weten dit, maar WordPress herkent automatisch een wp-config.php die één directory boven de webroot staat. Door het bestand te verplaatsen, is het niet meer via de browser bereikbaar - zelfs als je webserverconfiguratie een fout bevat.
De login-pagina beveiligen
De standaard login-pagina (/wp-login.php) is het populairste doelwit voor brute-force aanvallen. Er zijn meerdere lagen van bescherming die je kunt toepassen.
Two-factor authenticatie
Dit is de belangrijkste maatregel. Zelfs als een aanvaller je wachtwoord raadt, komt hij zonder de tweede factor niet binnen. Gebruik een plugin als WP 2FA of integreer met een authenticator-app.
Login-pogingen beperken
Beperk het aantal mislukte login-pogingen per IP-adres. Dit kan via een plugin, maar effectiever is het op NGINX-niveau:
# Rate limiting voor wp-login.php
limit_req_zone $binary_remote_addr zone=wplogin:10m rate=1r/s;
location = /wp-login.php {
limit_req zone=wplogin burst=3 nodelay;
include fastcgi_params;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
In ons artikel over PHP-FPM tuning bespraken we al hoe je NGINX en PHP-FPM optimaal laat samenwerken. Rate limiting past naadloos in dezelfde configuratie.
HTTP Basic Auth als extra laag
Voor sites waar alleen een vast team inlogt, kun je een extra authenticatielaag toevoegen:
location = /wp-login.php {
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
# ... fastcgi config
}
Dit stopt bots voordat ze überhaupt PHP raken - goed voor performance én security.
XML-RPC en REST API afsluiten
XML-RPC uitschakelen
XML-RPC (xmlrpc.php) is een legacy-interface die zelden nog nodig is. Het wordt actief misbruikt voor brute-force aanvallen en DDoS-amplificatie via de system.multicall-methode.
Schakel het uit in NGINX:
location = /xmlrpc.php {
deny all;
return 403;
}
Of via WordPress zelf:
add_filter('xmlrpc_enabled', '__return_false');
REST API beperken
De REST API is noodzakelijk voor de blok-editor (Gutenberg) en veel plugins. Volledig uitschakelen is geen optie, maar je kunt de toegang beperken tot ingelogde gebruikers:
add_filter('rest_authentication_errors', function ($result) {
if (true !== $result && !is_user_logged_in()) {
return new WP_Error(
'rest_not_logged_in',
'Authentication required.',
['status' => 401]
);
}
return $result;
});
Als je een headless WordPress-setup draait, is de REST API juist essentieel. Beveilig deze dan met application passwords of OAuth in plaats van openbare toegang.
Security headers configureren
HTTP-security headers vertellen de browser hoe hij met je site moet omgaan. Ze kosten niets qua performance en voegen een sterke beschermingslaag toe.
Configureer deze headers in NGINX:
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "camera=(), microphone=(), geolocation=()" always;
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline';" always;
Wat doet elke header?
- X-Frame-Options - voorkomt dat je site in een iframe wordt geladen (clickjacking-bescherming)
- X-Content-Type-Options - blokkeert MIME-type sniffing
- Referrer-Policy - beperkt welke informatie wordt meegestuurd bij uitgaande links
- Content-Security-Policy - bepaalt welke bronnen de browser mag laden (de krachtigste header, maar ook de meest complexe om goed in te stellen)
Als je Cloudflare als CDN gebruikt, kun je sommige headers ook daar configureren. Let op dat headers niet dubbel worden gezet.
WordPress-kern verharden
Bestandsbewerking uitschakelen
WordPress heeft een ingebouwde code-editor waarmee je thema- en pluginbestanden kunt bewerken vanuit het dashboard. Als een aanvaller admin-toegang krijgt, kan hij hier direct malware injecteren. Schakel het uit:
// wp-config.php
define('DISALLOW_FILE_EDIT', true);
Overweeg ook DISALLOW_FILE_MODS als je updates via de CLI of een deployment-pipeline afhandelt:
define('DISALLOW_FILE_MODS', true);
Versie-informatie verbergen
WordPress toont standaard het versienummer in de HTML-head en in RSS-feeds. Dit maakt het aanvallers makkelijk om te controleren of je een kwetsbare versie draait:
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
Database-prefix wijzigen
De standaard prefix wp_ is algemeen bekend. Hoewel security through obscurity geen echte beveiliging is, maakt een unieke prefix geautomatiseerde SQL-injectie-aanvallen lastiger. Stel dit in bij de installatie - achteraf wijzigen vereist handmatig databasewerk.
Beveiligingssleutels instellen
Zorg dat alle beveiligingssleutels en salts zijn ingesteld in wp-config.php. Deze sleutels worden gebruikt voor het versleutelen van cookies en sessie-informatie. Genereer ze opnieuw als je vermoedt dat je site gecompromitteerd is - dit logt automatisch alle gebruikers uit.
Updates en onderhoud
De meeste succesvolle aanvallen maken gebruik van bekende kwetsbaarheden waarvoor al een patch beschikbaar is. Updates zijn je eerste verdedigingslinie.
Automatische updates configureren
WordPress core minor-updates draaien standaard automatisch. Breid dit uit:
// Automatische minor-updates (standaard aan)
define('WP_AUTO_UPDATE_CORE', 'minor');
// Plugins en thema's automatisch updaten (optioneel)
add_filter('auto_update_plugin', '__return_true');
add_filter('auto_update_theme', '__return_true');
Automatische plugin-updates zijn een afweging. Ze houden je veilig, maar kunnen onverwachte problemen veroorzaken. Gebruik ze alleen als je een goede monitoring en een staging-omgeving hebt.
Ongebruikte plugins en thema's verwijderen
Deactiveren is niet genoeg - de code blijft op de server staan en kan exploitbaar zijn. Verwijder alles wat je niet actief gebruikt. Dit geldt ook voor standaard thema's die WordPress meelevert.
Webserver-level beveiliging
Veel beveiligingsmaatregelen zijn effectiever op serverniveau dan via WordPress zelf. Als je je server beheert (of een managed hosting-partij hebt die dit ondersteunt), configureer dan het volgende.
Gevoelige bestanden blokkeren
# Blokkeer toegang tot gevoelige bestanden
location ~* /(\.git|\.env|\.htaccess|wp-config\.php|readme\.html|license\.txt) {
deny all;
return 404;
}
# Blokkeer PHP-uitvoering in uploads
location ~* /wp-content/uploads/.*\.php$ {
deny all;
return 403;
}
Die laatste regel is bijzonder belangrijk. De uploads-map is schrijfbaar - als een aanvaller erin slaagt een PHP-bestand te uploaden, moet de server het weigeren uit te voeren.
Web Application Firewall
Een WAF zoals Cloudflare WAF of ModSecurity filtert kwaadaardig verkeer voordat het je applicatie bereikt. Dit beschermt tegen SQL-injectie, cross-site scripting (XSS) en andere OWASP Top 10-kwetsbaarheden.
In ons artikel over CDN-integratie met Cloudflare bespraken we al de basis. De WAF-functionaliteit is een logische volgende stap. Activeer op z'n minst de WordPress-specifieke managed rules.
Monitoring en incident response
Hardening is geen eenmalige actie. Je moet weten wat er op je site gebeurt.
Wat je moet monitoren
- Login-pogingen - zowel geslaagde als mislukte
- Bestandswijzigingen - onverwachte veranderingen in core-, plugin- of themabestanden
- Gebruikersaccounts - nieuwe admin-accounts die je niet hebt aangemaakt
- Uptime en beschikbaarheid - een gehackte site kan redirect-malware bevatten die je zelf niet ziet
Audit logging
Gebruik een plugin als WP Activity Log om alle acties in het dashboard te loggen. Dit is onmisbaar als meerdere mensen toegang hebben, en cruciaal bij het analyseren van een incident.
Vergeet ook de server-side logs niet. In een multi-server setup wil je logs centraal aggregeren.
Hardening-checklist
Gebruik deze checklist om je installatie systematisch door te lopen:
- Bestandsrechten correct ingesteld (755/644)
-
wp-config.phpbeveiligd (440) en optioneel verplaatst - Two-factor authenticatie voor alle admin-accounts
- Login-rate limiting op NGINX-niveau
- XML-RPC uitgeschakeld
- REST API beperkt tot geauthenticeerde gebruikers
- Security headers geconfigureerd
- Bestandsbewerking in dashboard uitgeschakeld
- Versie-informatie verborgen
- Beveiligingssleutels gegenereerd en ingesteld
- Automatische core-updates actief
- Ongebruikte plugins en thema's verwijderd
- PHP-uitvoering in uploads geblokkeerd
- WAF actief
- Audit logging ingeschakeld
- Staging-omgeving voor het testen van updates
Veelgestelde vragen
Wat is WordPress security hardening?
Security hardening is het proces waarbij je een WordPress-installatie systematisch beveiligt door aanvalsoppervlakken te verkleinen. Denk aan het verbergen van versie-informatie, het beperken van bestandsrechten, het afdwingen van sterke authenticatie en het toevoegen van beveiligingsheaders.
Is WordPress onveilig?
WordPress zelf wordt actief onderhouden en snel gepatcht. De meeste hacks ontstaan door verouderde plugins, zwakke wachtwoorden of verkeerde serverconfiguratie. Met goede hardening en regelmatige updates is WordPress een veilig platform.
Heb ik een security-plugin nodig voor WordPress?
Een security-plugin kan handig zijn als startpunt, maar veel maatregelen kun je beter op serverniveau configureren. Plugins zoals Wordfence of Sucuri voegen overhead toe. Combineer liever server-level hardening met een lichtgewicht plugin voor monitoring.
Hoe vaak moet ik WordPress en plugins updaten?
Zo snel mogelijk na een release, vooral bij security-patches. Stel automatische minor-updates in voor WordPress core en controleer minstens wekelijks op plugin-updates. Test updates altijd eerst op een staging-omgeving.
Wat is het verschil tussen een firewall en security hardening?
Een firewall (zoals een WAF) blokkeert kwaadaardig verkeer voordat het je site bereikt. Hardening verkleint het aanvalsoppervlak van je installatie zelf. Je hebt beide nodig - een firewall is geen vervanging voor een goed geharde WordPress-installatie.