WordPress security hardening: protect your site
Last updated: 31 December 2025
Basis WordPress beveiliging is een goede start, maar serieuze sites vereisen geavanceerde maatregelen. Dit artikel behandelt security hardening op server-, applicatie- en codeniveau.
Why Extra Hardening?
WordPress is het meest aangevallen CMS ter wereld. Niet omdat het onveilig is, maar omdat het zo populair is. Een standaard beveiligde site stopt 90% van de aanvallen. Hardening stopt de overige 10%.
Dreigingslandschap
- Brute force: Geautomatiseerd wachtwoorden raden
- Plugin-kwetsbaarheden: Verouderde of slechte code
- SQL injection: Database-manipulatie via invoervelden
- XSS: Kwaadaardige scripts injecteren
- File inclusion: Ongeautoriseerde bestanden uitvoeren
Server-Level Hardening
PHP Configuratie
Pas php.ini aan voor betere beveiliging:
; Verberg PHP-versie
expose_php = Off
; Beperk bestandsoperaties
open_basedir = /home/user/public_html:/tmp
; Schakel gevaarlijke functies uit
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
; Beperk includes tot eigen directory
allow_url_include = Off
allow_url_fopen = Off
; Session beveiliging
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1
Apache/Nginx Hardening
.htaccess (Apache):
# Blokkeer directe toegang tot gevoelige bestanden
<FilesMatch "^(wp-config\.php|readme\.html|license\.txt)">
Order allow,deny
Deny from all
</FilesMatch>
# Voorkom directory listing
Options -Indexes
# Blokkeer PHP-uitvoering in uploads
<Directory "/var/www/html/wp-content/uploads">
<FilesMatch "\.php$">
Order allow,deny
Deny from all
</FilesMatch>
</Directory>
# Bescherm .htaccess zelf
<Files .htaccess>
Order allow,deny
Deny from all
</Files>
# Security headers
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-XSS-Protection "1; mode=block"
Header always set Referrer-Policy "strict-origin-when-cross-origin"
Nginx equivalent:
# Blokkeer gevoelige bestanden
location ~* /(wp-config\.php|readme\.html|license\.txt) {
deny all;
}
# Geen PHP in uploads
location ~* /wp-content/uploads/.*\.php$ {
deny all;
}
# Security headers
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-XSS-Protection "1; mode=block" always;
Database Beveiliging
Gebruik een unieke database prefix (niet wp_):
$table_prefix = 'hr7x_';
Beperk database-gebruikersrechten:
-- Alleen noodzakelijke rechten
GRANT SELECT, INSERT, UPDATE, DELETE ON database.* TO 'wpuser'@'localhost';
-- Geen DROP, ALTER, GRANT rechten
wp-config.php Hardening
// Forceer SSL voor admin
define('FORCE_SSL_ADMIN', true);
// Blokkeer bestandswijzigingen via admin
define('DISALLOW_FILE_EDIT', true);
// Blokkeer plugin/theme installatie via admin
define('DISALLOW_FILE_MODS', true);
// Unieke salts (genereer op api.wordpress.org/secret-key)
define('AUTH_KEY', 'unieke-waarde-hier');
define('SECURE_AUTH_KEY', 'unieke-waarde-hier');
define('LOGGED_IN_KEY', 'unieke-waarde-hier');
define('NONCE_KEY', 'unieke-waarde-hier');
define('AUTH_SALT', 'unieke-waarde-hier');
define('SECURE_AUTH_SALT', 'unieke-waarde-hier');
define('LOGGED_IN_SALT', 'unieke-waarde-hier');
define('NONCE_SALT', 'unieke-waarde-hier');
// Beperk revisies
define('WP_POST_REVISIONS', 5);
// Automatische updates voor security
define('WP_AUTO_UPDATE_CORE', 'minor');
Bestandspermissies
Correcte permissies zijn cruciaal:
# Directories: 755
find /var/www/html -type d -exec chmod 755 {} \;
# Bestanden: 644
find /var/www/html -type f -exec chmod 644 {} \;
# wp-config.php extra beveiligd
chmod 600 wp-config.php
# Uploads directory mag schrijfbaar zijn
chmod 755 wp-content/uploads
Login Beveiliging
Verplaats wp-admin
// In wp-config.php
define('WP_ADMIN_DIR', 'geheim-admin-pad');
// In functions.php
add_filter('site_url', function($url, $path, $scheme) {
if ($path === 'wp-login.php' && !is_admin()) {
return str_replace('wp-login.php', WP_ADMIN_DIR, $url);
}
return $url;
}, 10, 3);
Two-Factor Authentication
Verplicht 2FA voor alle admins. Gebruik plugins zoals:
- Google Authenticator
- Duo Security
- Hardware keys (YubiKey)
Login Limiting
// Beperk inlogpogingen
function limit_login_attempts($user, $username, $password) {
$ip = $_SERVER['REMOTE_ADDR'];
$transient = 'login_attempts_' . md5($ip);
$attempts = get_transient($transient) ?: 0;
if ($attempts >= 5) {
return new WP_Error('too_many_attempts',
'Te veel inlogpogingen. Probeer over 15 minuten opnieuw.');
}
return $user;
}
add_filter('authenticate', 'limit_login_attempts', 30, 3);
function track_failed_login($username) {
$ip = $_SERVER['REMOTE_ADDR'];
$transient = 'login_attempts_' . md5($ip);
$attempts = get_transient($transient) ?: 0;
set_transient($transient, $attempts + 1, 15 * MINUTE_IN_SECONDS);
}
[add_action](/kennisbank/wordpress-hooks-uitleg)('wp_login_failed', 'track_failed_login');
Content Security Policy
CSP voorkomt XSS-aanvallen:
add_action('send_headers', function() {
header("Content-Security-Policy:
default-src 'self';
script-src 'self' 'unsafe-inline' https://trusted-cdn.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
img-src 'self' data: https:;
font-src 'self' https://fonts.gstatic.com;
connect-src 'self';
frame-ancestors 'self';
");
});
XML-RPC Uitschakelen
XML-RPC is een veelgebruikte aanvalsvector:
// Volledig uitschakelen
add_filter('xmlrpc_enabled', '__return_false');
// Of via .htaccess
<Files xmlrpc.php>
Order deny,allow
Deny from all
</Files>
REST API Beveiligen
Beperk de REST API voor niet-ingelogde gebruikers:
add_filter('rest_authentication_errors', function($result) {
if (!is_user_logged_in()) {
// Sta publieke endpoints toe
$public_routes = ['/wp/v2/posts', '/wp/v2/pages'];
$route = $_SERVER['REQUEST_URI'];
foreach ($public_routes as $public) {
if (strpos($route, $public) !== false) {
return $result;
}
}
return new WP_Error('rest_forbidden',
'Authenticatie vereist', ['status' => 401]);
}
return $result;
});
Monitoring en Logging
Activiteitenlog
function log_security_event($message, $level = 'info') {
$log_file = WP_CONTENT_DIR . '/security.log';
$timestamp = date('Y-m-d H:i:s');
$ip = $_SERVER['REMOTE_ADDR'];
$user = wp_get_current_user();
$username = $user->ID ? $user->user_login : 'anonymous';
$entry = "[{$timestamp}] [{$level}] [{$ip}] [{$username}] {$message}\n";
file_put_contents($log_file, $entry, FILE_APPEND | LOCK_EX);
}
// Log belangrijke acties
add_action('wp_login', function($username) {
log_security_event("Successful login: {$username}");
});
add_action('wp_login_failed', function($username) {
log_security_event("Failed login attempt: {$username}", 'warning');
});
File Integrity Monitoring
Controleer regelmatig of kernbestanden gewijzigd zijn:
# Genereer checksums
find /var/www/html/wp-includes -type f -name "*.php" \
-exec md5sum {} \; > /root/wp-checksums.txt
# Vergelijk later
md5sum -c /root/wp-checksums.txt 2>&1 | grep FAILED
Security Headers Testen
Test je configuratie op:
- securityheaders.com
- observatory.mozilla.org
- ssllabs.com/ssltest
Incident Response Plan
Bereid je voor op het ergste:
- Detectie: Monitoring alerts configureren
- Isolatie: Site offline halen indien nodig
- Analyse: Logs onderzoeken, besmetting identificeren
- Herstel: Schone backup terugzetten
- Preventie: Kwetsbaarheid dichten, hardening verbeteren
More information: WordPress.org documentatie
Frequently Asked Questions
How long does it take to implement this?
Implementation time varies per situation. Simple configurations can be done within an hour, more complex setups may take several hours to a day.
What are the costs?
Costs depend on your hosting provider and package. Many basic features are included for free, advanced features may incur additional costs.
Do I need technical knowledge?
You need little technical knowledge for the basics. Most hosting providers offer extensive documentation and support to help you.
Was this article helpful?
Compare hosting packages directly to find the best choice for your situation.
Related articles
What is web hosting? Explanation for beginners
Discover what web hosting is and how it works. Complete explanation about servers, domains and different hosting types for beginners.
What is VPS Hosting?
VPS hosting explained: what is a Virtual Private Server, who is it suitable for and what are the advantages compared to shared hosting?
What is an SSL Certificate?
Everything about SSL certificates: what is SSL, why do you need it and how do you recognize a secure website? Essential for every website.
What is Uptime in Web Hosting?
What does uptime mean in web hosting? Learn about uptime percentages, SLA guarantees and why 99.9% uptime is important for your website.
How much storage do I need for my website?
Discover how much disk space you really need for your website. Practical guide with examples per website type.