De meeste WordPress-beveiligingsteksten zijn vendor-marketing in de jas van educatie. Dit artikel niet. Het doel is een korte, geprioriteerde checklist die je vertelt wat je risico op compromittering in 2026 écht verlaagt, wat theater is en wat je precies moet intikken. Geschreven voor de site-eigenaar die al een securityplugin heeft geïnstalleerd, zich nog steeds niet veilig voelt en wil weten wat er nu moet gebeuren.
Eén getal om alles hieronder aan op te hangen. Volgens Patchstack's State of WordPress Security in 2026 zaten 91% van de 11.334 kwetsbaarheden die in 2025 in het WordPress-ecosysteem werden gemeld in plugins, 9% in thema's en minder dan 1% in de WordPress-core (zes kwetsbaarheden, allemaal lage prioriteit). De mediane tijd tussen publieke disclosure en massale exploitatie was vijf uur. Hardening gaat over die 91%, niet over de core.
Kortom: wat er in 2026 écht toe doet
Als je maar vijf dingen kunt doen, doe dan deze, in deze volgorde:
- Houd WordPress core, plugins en thema's automatisch gepatcht. Vijf uur is de mediaan. Handmatig patchen past niet in dat venster.
- Gebruik een password manager, unieke wachtwoorden en een tweede factor op elk adminaccount. De overgrote meerderheid van "hacks" zijn credential-compromissen, geen exploits.
- Beveilig
wp-login.phpenxmlrpc.phpmet rate limiting en 2FA. Die twee URL's krijgen vrijwel al het brute-force verkeer van een typische site. - Zet de juiste bestandsrechten en schakel de file editor in het dashboard uit. Een gekaapt adminaccount mag geen PHP-bestand via de theme editor kunnen uploaden.
- Maak backups die je minstens één keer hebt teruggezet en bewaar ze buiten de webserver. Een backup die je nooit hebt teruggezet is hoop, geen controle.
Alles hieronder is een uitwerking van die vijf. De latere secties zijn de referentie: exacte permission-waardes, wp-config constants en verificatiechecks die je kunt kopiëren.
Inhoudsopgave
- Waarom "hardening" niet hetzelfde is als "installeer een plugin"
- Houd WordPress, plugins en thema's automatisch gepatcht
- Gebruik een password manager en zet 2FA aan op elke admin
- Bestandsrechten en ownership strakzetten
- wp-login.php en xmlrpc.php afschermen
- File editor en file modifications uitzetten
- Loginpogingen limiteren en mislukte logins loggen
- HTTPS overal, met HSTS
- Backups als security control
- Securityplugins: wat ze wel en niet doen
- Referentie: het wp-config.php security blok
- Referentie: waardes voor bestandsrechten
- Mythes die je gewoon kunt laten varen
- Wanneer je hulp moet inschakelen
Waarom "hardening" niet hetzelfde is als "installeer een plugin"
Een WordPress-securityplugin draait ín WordPress. Dat is nuttig, en tegelijk een fundamentele beperking. Elke request die Wordfence, Sucuri of iThemes Security evalueert is al door de firewall, heeft je webserver bereikt, een PHP-worker opgestart, WordPress geladen en de controle aan de plugin overgedragen. Op dat moment mag de plugin kiezen om de request te blokkeren, maar de CPU en het workerslot zijn al besteed. Tijdens een grote aanval verzadigt de worker pool op de plugin zelf en gaat de site onderuit terwijl hij zichzelf verdedigt. Cloudways is in hun eigen analyse van Wordfence's architectuur vrij eerlijk over die limiet.
Hardening is de verzameling dingen die gebeuren vóór of buiten een plugin om. Correcte bestandsrechten hebben geen PHP nodig. TLS-terminatie, HSTS en rate limiting op de webserver gebeuren voordat een PHP-worker überhaupt wordt opgepakt. De file editor constant wordt door WordPress zelf gecontroleerd, niet door een plugin. Een 2FA-code op elke admin-login blokkeert het aanvalspad dat in echte incidenten dominant is. Niets daarvan vraagt om een plugin en het doet er meer toe dan welke plugin dan ook die je kunt installeren.
Daarom is dit artikel vendor-neutraal. Een securityplugin mág onderdeel zijn van een redelijke setup. Hij kán niet dé setup zijn.
Houd WordPress, plugins en thema's automatisch gepatcht
De hardening-stap met verreweg de grootste waarde is ook de minst glamoureuze: patch snel en patch automatisch. Het Patchstack-rapport van 2026 zet de mediane tijd tussen publieke disclosure en massale exploitatie op vijf uur. Zesenveertig procent van de kwetsbaarheden uit 2025 had op het moment van disclosure nog geen patch. Daar kun je niet handmatig op reageren. Automatisering is het enige geloofwaardige antwoord.
Het goede nieuws is dat automatische minor-updates al sinds WordPress 3.7 uit oktober 2013 de default zijn, en dus geen recent 6.x-fenomeen. Minor releases (X.Y.Z) bevatten vrijwel alle security-fixes en worden standaard stilletjes geïnstalleerd. Wat je zelf moet aanzetten zijn automatische updates voor plugins, thema's en major WordPress-releases. Alle drie zijn eenklikopties in wp-admin > Plugins, wp-admin > Weergave > Thema's en wp-admin > Dashboard > Updates. Zet ze aan voor alles wat je vertrouwt, en gooi weg wat je niet genoeg vertrouwt om automatisch te mogen updaten.
Voor ontwikkelaars is het equivalent op de command line:
# Automatische updates aanzetten voor een plugin via WP-CLI 2.10+
wp plugin auto-updates enable wordfence
# Automatische updates aanzetten voor een thema
wp theme auto-updates enable twentytwentyfour
# Major core automatische updates aanzetten (standaard alleen minor/security)
wp config set WP_AUTO_UPDATE_CORE true --raw
Je weet dat het werkt als wp plugin list --format=table in de kolom Auto-updates voor elke plugin die je hebt aangezet on toont.
Eén redactionele kanttekening. Auto-updates breken af en toe iets. Dat risico is echt, en het juiste antwoord is niet om ze uit te zetten; het juiste antwoord is ze combineren met een backupstrategie die binnen vijf minuten één plugin kan terugrollen. Kan jouw backup dat niet, dan is de backup de zwakke schakel, niet de update. Zie ook de sectie backups als security control verderop.
Verlaten plugins zijn de andere helft van dit verhaal. Een plugin die een jaar geen update heeft gekregen is een plugin die ook geen patch krijgt als zijn volgende CVE langskomt. De WordPress.org plugin directory toont tegenwoordig een waarschuwing op elke plugin die al meer dan twee jaar stilligt, en laat install count, rating en de "tested up to"-WordPress-versie zien. Behandel alles wat in twaalf maanden niet is aangeraakt als kandidaat voor vervanging, en alles zonder recente "tested up to" als impliciet al gecompromitteerd.
Gebruik een password manager en zet 2FA aan op elke admin
Gekaapte credentials zijn het aanvalspad dat het Patchstack-rapport niet hoeft te noemen omdat het zo dominant is dat het van de grafiek valt. Credential-aanvallen duiken niet op in kwetsbaarheidstellingen; ze duiken op in gestolen sessies, doorgestuurde password-reset mails en admins die op een site uit 2023 hetzelfde wachtwoord hebben hergebruikt. De fix is niet slim, maar operationeel.
Drie regels, op volgorde van belang:
- Elke administrator gebruikt een password manager. Geen uitzonderingen, ook jij niet. Bitwarden, 1Password en KeePassXC werken allemaal. Het wachtwoord dat de manager genereert is 20 tot 30 willekeurige tekens en je ziet het nooit. Zit een mens admin-wachtwoorden in te tikken, dan heb je de controle al verloren.
- Elke administrator heeft een tweede factor. WordPress levert out-of-the-box geen 2FA en je moet dat zelf toevoegen. De Two-Factor plugin die door het WordPress core-team wordt onderhouden is een juiste default voor developers; WP 2FA van Melapress is de wizard-gedreven default voor teams met niet-technische redacteuren. Beide ondersteunen TOTP (tijdgebaseerde codes) en passkeys (via een companion plugin bij Two Factor). De complete setup-walkthrough, inclusief de grace period die voorkomt dat je op dag één je team buitensluit, staat in tweestapsverificatie (2FA) voor WordPress.
- Elke administrator heeft een uniek e-mailadres dat zij persoonlijk beheren. De password-reset flow is een backup-authenticatiepad. Gedeelde
admin@jouwbedrijf.nl-mailboxen saboteren die flow.
Voor sites met meer dan één admin dwing je alle drie af met beleid, niet met hoop. Audit de gebruikerslijst elk kwartaal en verwijder ex-medewerkers op de dag dat ze vertrekken. Slapende adminaccounts zijn gewoon een compromittering die wacht op een trigger.
Eén detail over 2FA dat mensen in de war brengt: Application Passwords, geïntroduceerd in WordPress 5.6, vervangen cookie-gebaseerde logins of XML-RPC niet. Ze vullen die aan. Application Passwords bestaan zodat je een mobiele app of CI-pipeline een API-credential kunt geven zonder je hoofdwachtwoord te delen, én zodat je 2FA op interactieve logins kunt afdwingen zonder programmatische integraties kapot te maken. Voor dat doel zijn ze de moeite waard. Een brute-force verdediging zijn ze niet.
Bestandsrechten en ownership strakzetten
Bestandsrechten zijn de stilste hardening die je kunt doen, en de enige die overeind blijft na een gedeeltelijke compromittering. De WordPress hardening guide geeft de canonieke waardes: mappen op 755, bestanden op 644, wp-config.php op 440 of 400. De redenering is dat de webservergebruiker (www-data, nginx, apache) elk bestand moet kunnen lezen en elke map moet kunnen doorlopen, maar bijna nergens zou moeten kunnen schrijven. Alleen wp-content/uploads/ en (als je die gebruikt) wp-content/cache/ hoeven tijdens normaal gebruik schrijfbaar te zijn.
Twee commando's zetten dit correct op een typische Linux-host:
# Uitvoeren vanuit de WordPress-root. Ga uit van: webservergebruiker bezit de boom niet.
# Vervang /var/www/html door jouw installatiepad.
cd /var/www/html
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;
# wp-config.php bevat database-credentials en secret keys
chmod 440 wp-config.php
Ownership is iets anders dan permissions en minstens zo belangrijk. De bestanden zouden eigendom moeten zijn van een gebruiker die niet de webservergebruiker is, waarbij de webserver via de groep leestoegang krijgt. Een gangbaar patroon is chown -R deploy:www-data /var/www/html, zodat deploy (je SFTP-gebruiker) eigenaar is en www-data (de webserver) kan lezen. Die opzet betekent dat een gecompromitteerd PHP-proces geen thema- of plugin-bestanden kan overschrijven. En dat is precies het mechanisme dat de meeste backdoors gebruiken om persistent te worden. Voor de volledige referentie over FS_METHOD, ACL's en SELinux-contexten, zie WordPress-bestandsrechten.
Je weet dat het werkt als ls -la wp-config.php toont -r--r----- (mode 440) en stat -c '%a %U %G' . op de WordPress-root 755 laat zien met het verwachte eigenaar-paar.
Eén kanttekening. Sommige shared hosts draaien PHP als de site-eigenaar zelf (suPHP, FPM per-user pools), waardoor het split-ownership model niet werkt omdat PHP-proces en bestandseigenaar hetzelfde account zijn. Op zulke hosts is de hardening-winst kleiner en is de juiste compenserende maatregel om de dashboard file editor uit te zetten (volgende sectie) en je backups dicht bij de hand te houden.
wp-login.php en xmlrpc.php afschermen
wp-login.php en xmlrpc.php zijn waar het verkeer zit. Elke WordPress-site op het publieke internet krijgt een gestage motregen credential-stuffing op wp-login.php, en XML-RPC is de amplificatie-aanval: Sucuri beschrijft hoe de system.multicall-methode het mogelijk maakt om honderden gebruikersnaam/wachtwoord-combinaties in één POST-request te proberen, en hoe de pingback.ping-methode kan worden misbruikt om jouw site onderdeel te maken van een reflected DDoS. Een van beide eindpunten wagenwijd open laten staan is in 2026 geen nalatigheid meer, dat is een uitnodiging.
Twee paden, afhankelijk van hoe je deze eindpunten gebruikt.
Als je XML-RPC niet gebruikt (de meeste sites)
Schakel xmlrpc.php volledig uit op webserverniveau. De request mag PHP helemaal niet bereiken. Voor nginx:
# In het WordPress server block
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
return 444;
}
Voor Apache met .htaccess:
# In de .htaccess in de WordPress-root, boven het WordPress-block
Require all denied
De Jetpack-plugin en de klassieke WordPress-mobiele app gebruiken allebei XML-RPC, dus controleer of je het echt nodig hebt voordat je het uitschakelt. Moderne mobiele apps en headless setups gebruiken tegenwoordig de REST API, die via Application Passwords wordt geauthenticeerd. Let op dat de REST API ook een aanvalsoppervlak is voor gebruikerenumeratie; scherm die af als je geen publieke toegang tot gebruikers-endpoints nodig hebt.
Verificatie: draai curl -I https://jouwsite.nl/xmlrpc.php en controleer dat je 403 Forbidden of een gesloten verbinding terugkrijgt, geen 200 OK met een "XML-RPC server accepts POST requests only" body.
Voor wp-login.php
Bescherm die URL met drie lagen, in deze volgorde:
- Rate limiting op de webserver of WAF. Dit stopt brute force voordat het PHP bereikt. Kun je je webserver niet direct configureren, dan kan een reverse proxy zoals de gratis Cloudflare WAF het pad
jouwsite.nl/wp-login.phpbeperken tot vijf requests per minuut per IP. Die ene regel legt het overgrote deel van de geautomatiseerde aanvallen dood. - 2FA op elk adminaccount, zoals hierboven beschreven. Als een rate-limited login toch een goed wachtwoord vindt, stopt de tweede factor de compromittering.
- IP-allowlisting als je team vaste IP's heeft. Zet een
.htaccess- of nginxallow/deny-blok waarin alleen bekende IP's bijwp-login.phpmogen. Dit is de nucleaire optie en hij is uitstekend als hij toepasbaar is. Werken je admins vanuit koffietentjes of mobiele netwerken, dan past dit niet.
De login-URL veranderen naar jouwsite.nl/geheime-login/ staat niet in dit lijstje. Het vermindert opportunistisch geautomatiseerd verkeer, wat je logs beter leesbaar maakt, maar het vervangt geen rate limiting of 2FA. CVE-2024-2473 en CVE-2024-6289 hebben allebei verborgen login-URL's blootgelegd via bugs in de plugins die ze hoorden te verbergen. Obscuriteit is een log-schoonmaaktool, geen verdediging.
File editor en file modifications uitzetten
WordPress levert een plugin- en theme-editor in de admin-UI op wp-admin > Weergave > Thema-bestandseditor en wp-admin > Plugins > Plugin-bestandseditor. Een gekaapt adminaccount kan die gebruiken om binnen dertig seconden een PHP-bestand in wp-content/plugins/ of wp-content/themes/ te schrijven. Dat ene bestand wordt dan een persistente backdoor.
De editor staat in elke WordPress-versie standaard aan. WordPress 4.9 heeft wel een sandbox toegevoegd die fatal errors terugrolt die in de editor werden veroorzaakt, maar de editor zelf is toen niet uitgeschakeld. Wil je hem uit, dan zet je een constant in wp-config.php:
// Schakel de dashboard file editor voor thema's en plugins uit
define( 'DISALLOW_FILE_EDIT', true );
Voor sites waar de hele codebase vanuit een repository wordt gedeployed en er op de live server niks zou moeten veranderen, ga je een stap verder en zet je alle file modifications uit. Dat blokkeert ook plugin- en theme-installaties en -updates vanuit het dashboard:
// Schakel file edits EN plugin/theme install/update vanuit het dashboard uit
define( 'DISALLOW_FILE_MODS', true );
DISALLOW_FILE_MODS impliceert DISALLOW_FILE_EDIT; je hebt ze niet allebei nodig. Let op: dit schakelt ook de automatische update-flow vanuit WordPress zelf uit, wat betekent dat je updates ergens anders moet regelen (een CI-pipeline, wp-cli of een managed host). Voor sites met een gedisciplineerde deployment is dat prima. Voor sites zonder, is het rampzalig.
Je weet dat het werkt als wp-admin > Weergave geen "Thema-bestandseditor" meer in het submenu toont.
Loginpogingen limiteren en mislukte logins loggen
Rate limiting op de webserver (zie boven) is de eerste laag. WordPress zelf houdt mislukte logins niet bij en op de meeste hosts is de server-rate-limit een bot instrument. Een plugin vult het gat. Limit Login Attempts Reloaded is de minimale keuze en doet één ding goed: mislukte logins per IP tellen, het IP blokkeren vanaf een drempel en de poging loggen. Redelijke defaults zijn vier pogingen, een lockout van twintig minuten en een escalatie van vier uur na drie lockouts. Dat zijn toevallig ook de defaults van de plugin.
Draai je al een complete security suite, dan zit dit er bijna altijd al in. Stapel geen twee plugins die allebei mislukte logins tegen dezelfde database bijhouden; kies er eentje en laat die de functie beheren.
De audit-kant is net zo belangrijk als het blokkeren. Een log van mislukte logins vertelt je wanneer je site onder vuur ligt, welke gebruikersnamen aanvallers proberen (raden ze admin, dan is het rustig; raden ze je echte username, dan mikt iemand gericht op jou), en of je blocks standhouden. Controleer dat de eerste maand wekelijks en daarna maandelijks.
HTTPS overal, met HSTS
WordPress zonder HTTPS draaien is in 2026 niets wat nog iemand bewust doet; het is iets wat gebeurt omdat ooit iemand het heeft geconfigureerd en daarna niemand meer naar de details heeft gekeken. De checklist is kort maar de details doen er toe.
- Een geldig certificaat dat elke hostname dekt. Let's Encrypt via certbot voor self-hosted; wat de hosting-paneel biedt voor managed. Het certificaat moet zowel
jouwsite.nlalswww.jouwsite.nldekken als die allebei resolven. Een hostname-mismatch triggert een browserwaarschuwing en een daling in zoekverkeer. Meer over certificaattypen, levensduur en het DV/OV/EV-onderscheid staat in SSL-certificaten in WordPress. - Forceer HTTPS voor elke URL. De WordPress-kant staat in
wp-admin > Instellingen > Algemeen: zowel "WordPress-adres" als "Site-adres" beginnen methttps://. De webserver-kant is een 301-redirect vanhttp://naarhttps://voor elk pad. Een plugin kan dit ook, maar een webserverregel is sneller en is niet afhankelijk van een draaiende PHP. - Zet HSTS aan.
Strict-Transport-Security: max-age=31536000; includeSubDomains; preloadin je webserver-response-headers vertelt browsers een jaar lang geenhttp://meer te proberen voor jouw domein. Dat beschermt tegen actieve downgrade-aanvallen. De HSTS-referentie van MDN is de canonieke uitleg. - Los mixed content op. Als een pagina over HTTPS wordt geserveerd maar een
http://-afbeelding of script bevat, blokkeren browsers die resource. Draai Why No Padlock na activering van HTTPS tegen je homepage en fix alles wat hij meldt. De gebruikelijke boosdoener is hardcoded URL's in post-content; een search-and-replace in de database maakt het schoon.
Je weet dat het werkt als curl -I https://jouwsite.nl/ een 200 OK toont met een Strict-Transport-Security-header, en curl -I http://jouwsite.nl/ een 301 naar de HTTPS-versie toont.
Backups als security control
Een backup is het herstelplan dat elke andere controle veiliger maakt, omdat het de prijs van "zet de site van gisteravond terug en onderzoek in alle rust" lager maakt dan de prijs van "achterhaal om drie uur 's nachts op een zondag wat een aanvaller precies heeft gedaan". Die afweging is het hele punt. De regels:
- Dagelijkse geautomatiseerde backups, minimaal. Multi-auteur sites mogen uurlijks.
- Minstens één kopie buiten de webserver. Een backup in
wp-content/backups/is geen backup; een aanvaller met schrijfrechten opwp-content/kan hem verwijderen. Push backups naar S3, Backblaze B2, een andere server of een backup-dienst die van buiten naar binnen pullt. - Retentie van minstens 30 dagen. Compromitteringen worden vaak dagen of weken na dato ontdekt. Is je nieuwste backup al vergiftigd, dan heb je een oudere schone nodig.
- Een gedocumenteerde herstelprocedure die je minstens één keer hebt uitgevoerd. De eerste keer dat je uit backup terugzet mag niet tijdens een incident zijn. Doe elk kwartaal een droge oefening naar een staging-omgeving en klok de tijd. Werkt het herstel niet, dan bestaat de backup ook niet.
- Versleutel de backup at rest als hij je infrastructuur verlaat, zeker als er persoonsgegevens van AVG-scope in zitten.
Plugins die dit goed doen zijn UpdraftPlus, BackWPup en BackupBuddy; de meeste managed hosts draaien hun eigen systeem. De specifieke tool doet er minder toe dan die vier regels hierboven. Voor het volledige plan met retentie, off-site opslag en een kwartaal-restore-drill, zie WordPress-backupstrategie.
Securityplugins: wat ze wel en niet doen
Een securityplugin is een nuttige laag, geen complete verdediging. De eerlijke inventaris, voor de referentie-plugins (Wordfence, Sucuri, iThemes Security, All In One WP Security):
Wat ze redelijk goed doen:
- Melden als een bestand in
wp-content/onverwacht verandert. - Virtuele patches voor bekende CVE's toepassen, sneller dan jij de plugin zelf kunt updaten.
- Uploads en actieve bestanden scannen op bekende malware-signatures.
- De login-pagina omhullen met 2FA, rate limiting en CAPTCHA als je die niet apart wilt configureren.
- Je een mail sturen als een gebruiker wordt uitgesloten of een bestand verandert.
Wat ze om architecturale redenen niet kunnen:
- Requests blokkeren voordat PHP laadt. Elke request die zij zien heeft je workerpool al bereikt. Tijdens een grote aanval verzadigen de workers op de plugin zelf.
- Beschermen tegen server-misconfiguratie. Een
wp-config.phpdie wereldwijd leesbaar is, is voor de plugin onzichtbaar. - Een gekaapt adminaccount stoppen. Heeft de aanvaller een geldige sessie, dan ziet de plugin legitiem verkeer.
- Hun eigen scannerbelasting overleven op kleine hosts. Een volledige Wordfence-scan is CPU-zwaar; op een shared host van vijf euro per maand legt hij de site zelf al om.
- Backups, TLS of updates vervangen. Dat zijn andere disciplines.
Ga je er eentje evalueren, begin dan met Wordfence (de grootste community) of een WAF op hostingniveau (Cloudflare, Sucuri's cloudproxy) als je filtering wilt die gebeurt voordat requests je server raken. Hosting-niveau WAFs zijn strikt beter dan PHP-niveau plugins voor het blokkeren van verkeer; PHP-niveau plugins zijn strikt beter voor file monitoring.
Referentie: het wp-config.php security blok
Dit is het volledige wp-config.php-blok om te plakken, aangepast voor jouw site. Voeg het boven de regel /* That's all, stop editing! Happy blogging. */ in, onder de database- en $table_prefix-declaraties.
// ----- Security hardening blok -----
// Dashboard file editor uitzetten (thema + plugin editor)
define( 'DISALLOW_FILE_EDIT', true );
// Automatische updates voor major WordPress-releases aanzetten.
// Minor/security updates worden sinds 3.7 automatisch geïnstalleerd.
define( 'WP_AUTO_UPDATE_CORE', true );
// Forceer alle admin-requests over HTTPS. Gaat ervan uit dat je site op HTTPS draait.
define( 'FORCE_SSL_ADMIN', true );
// PHP-geheugen alleen tijdens beheertaken (imports, updates) verhogen.
// Geldt NIET voor front-end page loads.
define( 'WP_MEMORY_LIMIT', '128M' );
define( 'WP_MAX_MEMORY_LIMIT', '256M' );
// Debug: schrijf errors naar een bestand, toon ze nooit op het scherm in productie.
define( 'WP_DEBUG', false ); // alleen tijdens diagnose op true zetten
define( 'WP_DEBUG_LOG', true ); // schrijft naar wp-content/debug.log
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );
// Maximaal 5 post revisies per post (minder DB-bloat en minder aanvalsoppervlak).
define( 'WP_POST_REVISIONS', 5 );
// Prullenbak automatisch elke 30 dagen legen.
define( 'EMPTY_TRASH_DAYS', 30 );
// ----- Einde security hardening blok -----
Twee optionele regels voor deployment-vanuit-git setups:
// Schakel ALLE file modifications vanuit het dashboard uit:
// theme/plugin editor, plugin install, plugin update, theme install.
// Vereist dat updates buiten WP om worden gedaan (CI, wp-cli, managed host).
define( 'DISALLOW_FILE_MODS', true );
// Weiger ongefilterde HTML van elke rol, inclusief administrator.
// Alleen aanzetten als geen enkele legitieme auteur ruwe HTML in posts plakt.
define( 'DISALLOW_UNFILTERED_HTML', true );
Plak die laatste twee niet zonder te begrijpen wat je uitzet. DISALLOW_FILE_MODS sloopt de complete update-flow uit het dashboard. DISALLOW_UNFILTERED_HTML kan contentworkflows breken voor sites die embed-code van derden in posts plakken.
Referentie: waardes voor bestandsrechten
De volledige tabel, gelijk aan de WordPress core hardening guide:
| Pad | Permissions | Octaal | Waarom |
|---|---|---|---|
/ (WordPress-root) |
drwxr-xr-x |
755 |
Map traversal door webserver, geen group- of other-write |
| Alle mappen onder de root | drwxr-xr-x |
755 |
Idem |
| Alle bestanden onder de root | -rw-r--r-- |
644 |
Leesbaar voor webserver, schrijfbaar alleen voor eigenaar |
wp-config.php |
-r--r----- |
440 |
Bevat DB-credentials en secret keys; alleen leesbaar voor group (webserver) |
wp-content/uploads/ |
drwxr-xr-x |
755 |
Moet schrijfbaar zijn door de eigenaar die PHP draait (niet anderen) |
wp-content/uploads/* |
-rw-r--r-- |
644 |
Geüploade bestanden zijn niet uitvoerbaar |
.htaccess (alleen Apache) |
-rw-r--r-- |
644 |
Apache leest hem bij elke request |
Ownership. De boom moet eigendom zijn van een niet-webserver-gebruiker (deploy, wordpress, het SFTP-account), met de webservergebruiker (www-data, nginx, apache) in de group. Dat betekent dat PHP leest via group-rechten en dat het niet kan schrijven buiten de uploads-map, wat precies de plek is waar je wilt dat een backdoor stukloopt.
Eén uitzondering die het noemen waard is. Sommige plugins hebben tijdens install of update écht schrijftoegang nodig tot wp-content/ (caching-plugins die config-bestanden genereren, vertaalplugins die taalpacks downloaden). Blokkeer je dat, dan blokkeer je de plugin. Het schoonste antwoord is tijdelijk write-toegang geven tijdens de update en daarna terugdraaien. DISALLOW_FILE_MODS plus een externe deployment-pipeline is het structurele antwoord voor sites waar dit echt telt.
Mythes die je gewoon kunt laten varen
Een kort lijstje van dingen die mensen doen die niet helpen, en waarom niet.
"Ik heb de login-URL veranderd in /mijn-geheime-login/, dus ik zit veilig." Je zit niet veilig; je hebt je bot-logs rustiger gemaakt. Moderne vulnerability scanners bevatten login-path discovery, en twee CVE's in 2024 (CVE-2024-2473 onder andere) lieten aanvallers de verborgen URL lekken via bugs in de verbergplugin zelf. Rate limiting en 2FA doen het echte werk.
"Ik heb een securityplugin geïnstalleerd, dus hoef ik niet te updaten." De securityplugin is ook een plugin. Die heeft ook kwetsbaarheden. Wordfence's eigen advisory-geschiedenis is openbaar; Sucuri en iThemes hebben vergelijkbare lijstjes. Updates zijn de controle.
"WordPress is onveilig." De WordPress-core had in 2025 zes kwetsbaarheden, allemaal lage prioriteit. 91% van de kwetsbaarheden in het ecosysteem zat in plugins. Het frame klopt niet; de plugins die jij hebt gekozen zijn het verhaal.
"Mijn site is te klein om aan te vallen." Geautomatiseerde aanvallen mikken niet, die scannen. Een site met tien bezoekers per dag krijgt dezelfde brute-force-motregen als een site met tienduizend. Je bent een nummer in een lijst.
"wp-admin achter HTTP Basic Auth verstoppen is genoeg." Het is een nuttige laag, vooral tegen drive-by-scanners en brute force, en de WordPress hardening guide raadt het aan. Maar Basic Auth-credentials zijn herbruikbaar en worden bij elke request meegestuurd; de echte verdediging blijft een sterk wachtwoord plus 2FA daarachter.
Wanneer je hulp moet inschakelen
Bel een specialist als één van deze dingen waar is, en verzamel de lijst hieronder voordat je belt. Elke minuut die zij uitsparen op context is een minuut dichter bij je site terug in de lucht.
- Een securityscan (vanuit een zoekmachine, je hosting-provider of Sucuri/VirusTotal) meldt je site als gecompromitteerd.
- Je ziet onverwachte adminaccounts, onverwachte posts of onverwachte redirects naar vreemde domeinen. Past dit bij jouw situatie, dan loopt het artikel WordPress gehackt / malware-redirect opruimen de volledige incident response door.
- Je host stuurt een waarschuwing over malware of phishing vanaf je site.
- Een backup-restore levert geen schone site op, en ook de backup daarvoor is vuil.
- Je probeerde hardening toe te passen, en de site brak op een manier die je niet kunt verklaren.
Verzamel voordat je vraagt:
- De WordPress-versie, PHP-versie en het actieve thema.
- Een lijst van actieve plugins met versies (uit
wp plugin list --format=csvofwp-admin > Plugins). - De meest recente regels uit
wp-content/debug.logals die bestaat. - De meest recente regels uit de access- en error-logs van je webserver.
- Een lijst adminaccounts en de aanmaakdatum van elk.
- Of je een betrouwbare backup hebt en hoe oud die is.
- Een tijdlijn van wat er in de 72 uur voor de symptomen veranderde.
Zijn de symptomen een login die je niet meer kunt bereiken in plaats van een zichtbare compromittering, dan vind je de volledige diagnose-flow in niet kunnen inloggen op WordPress. Voor het specifieke geval van een login die wel lukt en je dan weer terugzet, zie WordPress login redirect loop. Heeft je hardening-werk wp-config.php gesloopt en is de site nu leeg, dan staat het herstelpad in white screen of death in WordPress.