Come funziona questo controllo
Questo controllo agisce solo se il tuo sito è WordPress, e lo rileva cercando wp-content o wp-includes nell'HTML della pagina principale. Se non compaiono, non fa nulla. Se compaiono, prova tre fughe abituali. Prima: il tag <meta name="generator" content="WordPress 6.x"> nell'HTML, che rivela la versione esatta (gravità bassa). Seconda: il file /readme.html, che WordPress include in ogni installazione e che pure indica la versione (bassa). Terza: la rotta /wp-json/wp/v2/users della REST API; se risponde 200 con JSON contenente i campi slug e name, sta consegnando la lista degli utenti con il loro nome di login (gravità media).
Perché è importante
WordPress muove oltre il 40 % del web, quindi è il bersaglio preferito degli attacchi automatizzati. Quegli attacchi funzionano in due passi: identificare versione e plugin per scegliere l'exploit, poi provare password contro il login. La versione esposta risolve il primo passo. La lista degli utenti risolve metà del secondo: con lo slug di ogni utente (che è il nome di login, non il nome visibile), all'attaccante manca solo la password, e quella di admin, editor o del nome del proprietario viene provata a migliaia al minuto. Per questo l'enumerazione degli utenti ha gravità media e le altre due bassa.
Come risolvere
Versione nel meta generator
Nel functions.php del tuo tema figlio o in un piccolo plugin tuo:
remove_action('wp_head', 'wp_generator');
Tieni presente che la versione si vede anche nei parametri ?ver=6.x dei CSS e JS del core. Nasconderla del tutto richiede un plugin di sicurezza; ma ciò che ti protegge davvero è tenere WordPress aggiornato, non nascondere il numero.
readme.html
Cancellalo dopo ogni installazione e aggiornamento (WordPress lo ricrea), oppure bloccalo sul server. In nginx: location = /readme.html { return 404; }. In Apache, nel .htaccess: <Files readme.html> Require all denied </Files>. Fai lo stesso con license.txt.
Enumerazione degli utenti
Limita la rotta degli utenti della REST API alle sessioni autenticate. Senza plugin, nel functions.php:
add_filter('rest_endpoints', function ($endpoints) {
if (!is_user_logged_in()) {
unset($endpoints['/wp/v2/users']);
unset($endpoints['/wp/v2/users/(?P<id>[\d]+)']);
}
return $endpoints;
});
I plugin di sicurezza abituali (Wordfence, Solid Security, All-In-One Security) hanno un'opzione equivalente. Chiudi anche la vecchia enumerazione via ?author=1, che reindirizza a /author/nome/, e metti limite di tentativi e doppio fattore sul login: anche se il nome utente trapela, la password da sola non basta più.
Verifica che sia risolto
curl -s https://tuodominio.it | grep -io '<meta name="generator"[^>]*>'
curl -s -o /dev/null -w "%{http_code}\n" https://tuodominio.it/readme.html
curl -s -o /dev/null -w "%{http_code}\n" https://tuodominio.it/wp-json/wp/v2/users
Atteso: il primo non restituisce nulla; il secondo, 404 o 403; il terzo, 401 o 403 (o 404 se hai eliminato la rotta).
Domande frequenti
Non basta rinominare l'utente "admin"?
Aiuta contro gli attacchi più stupidi, ma se la REST API elenca gli utenti, il nome nuovo si scopre con una richiesta. Rinominalo e chiudi l'enumerazione.
Il mio tema o un plugin usa la REST API degli utenti nel front end.
È raro, ma succede con alcune directory di autori. Allora, invece di togliere la rotta, limita i campi che restituisce (senza slug) o restringila per capacità utente. Provalo prima in un ambiente di staging.
Questo controllo guarda i plugin vulnerabili?
No; guarda le fughe dell'installazione base. I plugin non aggiornati sono rilevati in parte da librerie obsolete. E se hai attivato WP_DEBUG_LOG, il file pubblico che genera è coperto da log esposti.