Ga naar inhoud

WordPress security hardening: geavanceerde beveiliging

Laatst bijgewerkt: 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.

Waarom 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/thema 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:

  1. Detectie: Monitoring alerts configureren
  2. Isolatie: Site offline halen indien nodig
  3. Analyse: Logs onderzoeken, besmetting identificeren
  4. Herstel: Schone backup terugzetten
  5. Preventie: Kwetsbaarheid dichten, hardening verbeteren

Meer informatie: WordPress.org documentatie

Veelgestelde vragen

Hoe lang duurt het om dit te implementeren?

De implementatietijd varieert per situatie. Voor eenvoudige configuraties is dit binnen een uur geregeld, complexere setups kunnen enkele uren tot een dag duren.

Wat zijn de kosten?

De kosten zijn afhankelijk van je hosting provider en pakket. Veel basisfuncties zijn gratis inbegrepen, voor geavanceerde functies kunnen extra kosten gelden.

Heb ik technische kennis nodig?

Voor de basis heb je weinig technische kennis nodig. De meeste hosting providers bieden uitgebreide documentatie en support om je te helpen.

Was dit artikel nuttig?

Vergelijk direct hosting pakketten om de beste keuze voor jouw situatie te maken.

Klaar om te kiezen?

Vergelijk hosting pakketten