25 Tecniche di Hardening WordPress: Dalla Più Facile alla Più Paranoica
Il hardening è il processo di ridurre la superficie di attacco di un sistema. Su WordPress, significa chiudere porte che non dovrebbero essere aperte, rimuovere informazioni che non dovrebbero essere visibili, e limitare i danni se qualcuno riesce a entrare.
Queste 25 tecniche sono ordinate per impatto e difficoltà. Le prime 10 le fai in un’ora. Le successive 10 in mezza giornata. Le ultime 5 sono per chi gestisce siti ad alto rischio (PA, e-commerce, finanza).
Livello 1: Le 10 Basi (1 ora)
1. Disabilita l’editor di file in wp-admin
// wp-config.php
define('DISALLOW_FILE_EDIT', true);
Impedisce la modifica di plugin e temi da wp-admin. Se un attaccante ottiene accesso admin, non può iniettare codice direttamente dall’interfaccia.
2. Blocca xmlrpc.php
# Nginx
location = /xmlrpc.php { deny all; }
# Apache (.htaccess)
<Files xmlrpc.php>
Require all denied
</Files>
xmlrpc.php è il vettore #1 per brute force amplificati. A meno che non usi Jetpack o l’app WordPress mobile, bloccalo.
3. Rimuovi la versione di WordPress dal frontend
// functions.php o mu-plugin
remove_action('wp_head', 'wp_generator');
add_filter('the_generator', '__return_empty_string');
Non è sicurezza reale (un attaccante determinato trova la versione in altri modi), ma riduce il rumore degli scanner automatici.
4. Cambia il prefisso tabelle database
Se stai installando WordPress da zero, cambia il prefisso da wp_ a qualcosa di unico (xk7_, cms2026_). Complica le SQL injection che assumono il prefisso di default.
Su installazioni esistenti: fattibile ma rischioso. Meglio non toccare se il sito è in produzione.
5. Disabilita l’enumerazione utenti
# Nginx: blocca ?author=N
if ($args ~* "author=") {
return 403;
}
// Oppure via PHP (functions.php)
add_action('template_redirect', function() {
if (isset($_GET['author'])) {
wp_redirect(home_url(), 301);
exit;
}
});
Impedisce agli attaccanti di scoprire gli username tramite ?author=1, ?author=2, etc.
6. Limita i tentativi di login
Wordfence lo fa di default. Senza plugin: usa Limit Login Attempts Reloaded. Configurazione raccomandata: 5 tentativi, lockout 30 minuti, reset dopo 24 ore.
7. Forza password forti
// Impedisci password deboli
add_action('user_profile_update_errors', function($errors, $update, $user) {
if (strlen($user->user_pass) < 12) {
$errors->add('weak_password', 'La password deve avere almeno 12 caratteri.');
}
}, 10, 3);
8. Disabilita la REST API per utenti non autenticati (selettivo)
add_filter('rest_authentication_errors', function($result) {
if (true === $result || is_wp_error($result)) return $result;
if (!is_user_logged_in()) {
// Permetti solo endpoint pubblici necessari
$allowed = ['/wp/v2/posts', '/wp/v2/pages', '/wp/v2/categories'];
$route = $_SERVER['REQUEST_URI'] ?? '';
foreach ($allowed as $endpoint) {
if (strpos($route, $endpoint) !== false) return $result;
}
return new WP_Error('rest_not_logged_in', 'Autenticazione richiesta.', ['status' => 401]);
}
return $result;
});
9. Proteggi wp-config.php
# Permessi file
chmod 600 wp-config.php
# Nginx: blocca accesso diretto
location = /wp-config.php { deny all; }
# Apache
<Files wp-config.php>
Require all denied
</Files>
10. Abilita auto-update per minor releases
// wp-config.php (di default è già attivo, ma verifica)
define('WP_AUTO_UPDATE_CORE', 'minor');
Livello 2: Le 10 Avanzate (mezza giornata)
11. Security Headers HTTP
Coperti in dettaglio nel nostro articolo dedicato ai security headers. Le 6 righe che bloccano clickjacking, XSS, MIME sniffing.
12. Blocca esecuzione PHP in wp-content/uploads
# Nginx
location ~* /wp-content/uploads/.*\.php$ { deny all; }
# Apache (.htaccess in wp-content/uploads/)
<Files "*.php">
Require all denied
</Files>
Il 56% delle backdoor WordPress sono file PHP nella directory uploads (dato Sucuri). Questa singola regola le rende inutilizzabili.
13. Disabilita directory listing
# Nginx (di default è off)
autoindex off;
# Apache
Options -Indexes
14. Limita le dimensioni upload
# Nginx
client_max_body_size 10M;
# php.ini
upload_max_filesize = 10M
post_max_size = 12M
15. Proteggi .htaccess e altri file sensibili
# Nginx
location ~* /\.(htaccess|htpasswd|ini|log|sh|sql|bak|config)$ {
deny all;
}
16. Disabilita il debug in produzione
// wp-config.php
define('WP_DEBUG', false);
define('WP_DEBUG_DISPLAY', false);
define('WP_DEBUG_LOG', false); // O true ma con path custom fuori dalla web root
17. Usa chiavi univoche per i cookie
// wp-config.php - rigenera periodicamente
define('AUTH_KEY', 'valore-unico-lungo-casuale');
define('SECURE_AUTH_KEY', 'altro-valore-unico');
// ... tutte e 8 le chiavi da https://api.wordpress.org/secret-key/1.1/salt/
18. Limita l’accesso a wp-admin per IP
# Nginx - Solo per IP specifici (ufficio, VPN)
location /wp-admin {
allow 203.0.113.0/24; # IP ufficio
allow 10.0.0.0/8; # VPN
deny all;
# Permetti admin-ajax.php per tutti (usato dal frontend)
location = /wp-admin/admin-ajax.php {
allow all;
}
}
Misura drastica. Usala solo se hai IP fissi o VPN. Se lavori da casa con IP dinamico, non è praticabile.
19. Database: utente con privilegi minimi
-- Crea utente MySQL con solo i privilegi necessari per WordPress
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, ALTER, INDEX, DROP
ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
Non dare GRANT, SUPER, FILE, o PROCESS all’utente WordPress. Non ne ha bisogno.
20. Monitora i file modificati
# Script cron: segnala file PHP modificati nelle ultime 24 ore
find /var/www/html -name "*.php" -mtime -1 -not -path "*/cache/*" | \
mail -s "File PHP modificati" admin@tuosito.com
Livello 3: Le 5 Paranoiche (siti ad alto rischio)
21. WAF esterno (Cloudflare o Sucuri)
Il traffico malevolo non arriva mai al server. Necessario per DDoS protection seria.
22. File system read-only per il core
# Rendi il core WordPress non scrivibile
chattr +i wp-config.php
chattr +i wp-login.php
# I file core non possono essere modificati nemmeno da root
23. Isolamento dei siti (container per sito)
Ogni sito WordPress in un container Docker separato. Se uno viene compromesso, gli altri sono isolati.
24. Fail2ban per WordPress
# /etc/fail2ban/filter.d/wordpress.conf
[Definition]
failregex = ^<HOST> .* "POST /wp-login.php
^<HOST> .* "POST /xmlrpc.php
# /etc/fail2ban/jail.local
[wordpress]
enabled = true
filter = wordpress
logpath = /var/log/nginx/access.log
maxretry = 5
bantime = 3600
25. Audit di sicurezza professionale
Pen test annuale da un professionista esterno. Nessun tool automatico sostituisce un occhio esperto che cerca le vulnerabilità logiche, non solo quelle tecniche.
FAQ
Devo fare tutte e 25?
Le prime 10 sono obbligatorie per qualsiasi sito in produzione. Le 11-20 sono fortemente raccomandate per agenzie e siti professionali. Le 21-25 sono per siti PA, e-commerce, o con dati sensibili.
Queste tecniche rallentano il sito?
No. La quasi totalità sono configurazioni server o WordPress che non aggiungono elaborazione. Le uniche con potenziale impatto: WAF esterno (aggiunge un hop di rete, ma di solito migliora le performance grazie alla CDN) e fail2ban (trascurabile).
Posso automatizzare il hardening?
Sì. Crea uno script bash che applica le tecniche 1-16 su ogni nuova installazione WordPress. Per le agenzie, è un checklist da eseguire a ogni setup. GEO Optimizer include un check sugli header e meta tag nella sua audit routine.