Brute force su wp-login: come fermare gli attacchi senza bloccare gli utenti legittimi

Gli attacchi brute force su wp-login.php sono costanti e automatizzati. Il rischio non è solo la password scoperta: è il server che cede sotto i tentativi. Rate limiting, WAF, 2FA e reCAPTCHA — in quale ordine applicarli e perché la protezione mal fatta blocca gli utenti veri.
Se hai un sito WordPress pubblico, wp-login.php è sotto attacco in questo momento. Non è un'allerta: è la normalità. Bot automatizzati scansionano continuamente il web alla ricerca di installazioni WordPress e tentano liste di password note. La maggior parte dei tentativi fallisce, ma il volume è tale da consumare risorse del server e, ogni tanto, trovare una password debole.
Il danno del brute force non è solo la violazione dell'account. È il carico: migliaia di richieste al secondo su wp-login.php saturano le risorse PHP, rallentano il sito per tutti gli utenti legittimi e, sui hosting condivisi, possono far cadere l'intero server. Fermare l'attacco è necessario; farlo senza bloccare gli utenti veri è la parte che molti sbagliano.
Perché il blocco per IP non basta (e a volte peggiora)
La prima reazione è bloccare gli IP dopo N tentativi falliti. Funziona, ma ha due limiti. Primo: gli attaccanti usano reti distribuite (botnet), quindi l'IP cambia a ogni tentativo — il blocco non li ferma. Secondo, e peggiore: gli IP condivisi. Se blocchi l'IP di un ufficio dopo 5 tentativi, blocchi tutti gli utenti di quell'ufficio, inclusi quelli legittimi che non hanno fatto nulla. Su reti aziendali e operatori che usano NAT, il blocco IP cieco è un modo efficace di negare l'accesso ai tuoi stessi utenti.
Il rate limiting va fatto, ma con intelligenza: sul numero di tentativi per IP, con soglie ragionevoli (non 3, ma 10-20), e con una finestra di blocco che scade (15-30 minuti, non permanente). E va combinato con altre difese, non usato da solo.
// Rate limiting su wp-login con soglie ragionevoli (functions.php o MU-plugin)
add_action( 'wp_login_failed', function( $username ) {
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
$key = 'login_fails_' . md5( $ip );
$attempts = (int) get_transient( $key ) + 1;
set_transient( $key, $attempts, 30 * MINUTE_IN_SECONDS );
// Blocca dopo 10 tentativi, non 3: evita di bloccare uffici interi
if ( $attempts > 10 ) {
set_transient( 'login_blocked_' . md5( $ip ), true, 20 * MINUTE_IN_SECONDS );
}
});
add_filter( 'authenticate', function( $user, $username ) {
$ip = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
if ( get_transient( 'login_blocked_' . md5( $ip ) ) ) {
return new WP_Error( 'too_many_attempts', 'Troppi tentativi. Riprova tra 20 minuti.' );
}
return $user;
}, 30, 2 );Il WAF ferma l'attacco prima di WordPress
Il rate limiting a livello PHP funziona, ma ogni tentativo consuma comunque una richiesta PHP completa — il server lavora comunque. Un Web Application Firewall (WAF) a livello server o CDN ferma i tentativi prima che raggiungano WordPress. Cloudflare, con le regole di rate limiting gestite, è l'esempio più accessibile:
# Regola di rate limiting Cloudflare (via dashboard o API)
# Blocca dopo 5 richieste POST a wp-login.php in 60 secondi per IP
#
# Via API Cloudflare:
curl -X POST "https://api.cloudflare.com/client/v4/zones/{zone}/rulesets" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
--data '{
"rules": [{
"expression": "(http.request.uri.path eq \"/wp-login.php\" and http.request.method eq \"POST\")",
"action": "block",
"ratelimit": { "characteristics": ["ip.src"], "period": 60, "requests_per_period": 5 }
}]
}'2FA: l'ultima difesa che rende il brute force inutile
Anche con rate limiting e WAF, un attaccante determinato con una password giusta entra. L'autenticazione a due fattori (2FA) rende la password sola insufficiente: serve anche un codice temporaneo dal telefono dell'utente. Anche se la password viene scoperta, l'attaccante non ha il secondo fattore. Per gli account amministrativi il 2FA non è opzionale — è la singola misura che più riduce il rischio reale di compromissione.
reCAPTCHA: utile, ma con cautela
Aggiungere reCAPTCHA al login riduce i bot automatizzati, ma ha un costo: peggiora l'esperienza dell'utente legittimo (il «trova i semafori»), aggiunge JavaScript di terze parti che impatta le prestazioni e la privacy, e non ferma gli attacchi gestiti da servizi di risoluzione captcha a pagamento. Usalo come strato aggiuntivo, non come difesa principale. La difesa principale è WAF + rate limiting + 2FA.
L'ordine corretto degli interventi
La sequenza che funziona, dal più efficace al meno invasivo: primo, WAF a livello server/CDN che ferma il volume prima di WordPress. Secondo, rate limiting con soglie tolleranti per non bloccare gli utenti veri. Terzo, 2FA su tutti gli account amministrativi — la misura che rende la password sola inutile. Quarto, reCAPTCHA solo se i precedenti non bastano, e consapevoli del costo in UX e prestazioni.
L'errore più comune è applicare le difesi nell'ordine sbagliato: reCAPTCHA come prima linea (fastidio per gli utenti, inefficace contro bot avanzati) e 2FA come opzionale (quando è la difesa più forte). Inverti l'ordine e l'attacco diventa molto più difficile da portare a termine — senza che l'utente legittimo se ne accorga.
Verifica la sicurezza del tuo WordPress prima che diventi un'emergenza.
Un audit di sicurezza individua le falle, i plugin vulnerabili e le configurazioni deboli prima che qualcuno le sfrutti.
Articoli correlati

Hardening WordPress: 12 controlli per blindare un sito prima che venga attaccato
Leggi
Truffe sui domini: quando il tuo sito non è davvero tuo e come difenderti
Leggi
