Questo articolo è stato pubblicato per la prima volta nel 2012 e completamente riscritto a ottobre 2026: i commenti più vecchi si riferiscono alla versione originale.
Nel 2012 guardavo i log dei miei server e vedevo centinaia di tentativi al giorno contro wp-login.php, così avevo fatto quello che faceva mezzo mondo WordPress in quegli anni: un plugin per bloccare gli IP dopo tre errori e, soprattutto, uno snippet .htaccess che nascondeva la pagina di login dietro un indirizzo segreto, perché qualche cliente aveva deciso che la data di nascita del figlio fosse una password più che dignitosa. Funzionava, più o meno, e mi faceva sentire molto furbo; a rileggerlo oggi mi fa sorridere, un po’ come le foto di quando avevo i capelli.
Quattordici anni dopo gli attacchi brute force contro WordPress non sono spariti, anzi sono diventati più distribuiti e più pazienti, ma nel frattempo sono cambiati gli strumenti per difendersi: WordPress salva le password con bcrypt, esistono le application password, l’autenticazione a due fattori e le passkey sono alla portata di chiunque, e il traffico malevolo si può fermare prima ancora che arrivi al server. Qui rimetto in fila le difese che hanno senso nel 2026 e quelle che, con tutto l’affetto per il me stesso del 2012, possiamo lasciare in soffitta.
Come funziona un attacco brute force oggi
Un attacco brute force contro WordPress consiste nel provare in automatico migliaia di combinazioni di nome utente e password sul form di wp-login.php o sull’endpoint xmlrpc.php, sperando che prima o poi una combinazione funzioni. Il problema è doppio: c’è il rischio che un account con una password debole venga violato, e c’è il costo di tutte quelle richieste, che arrivano a PHP e al database e rallentano il sito anche quando nessuna va a segno.
Oggi gli attacchi arrivano raramente da un singolo indirizzo che si può bloccare a mano: più spesso sono distribuiti su reti di macchine compromesse, ruotano gli IP e si limitano a pochi tentativi per indirizzo, proprio per non far scattare i blocchi più ingenui. Molto diffuso è anche il credential stuffing, in cui l’attaccante riusa credenziali rubate ad altri servizi, puntando sull’abitudine di usare la stessa password ovunque.
La conseguenza pratica è che nessuna singola misura risolve il problema, mentre alcune difese a strati, semplici e ben configurate, lo riducono a un rumore di fondo.
Password, application password, 2FA e passkey
La prima linea di difesa è anche la meno spettacolare: password lunghe e uniche, generate e conservate da un password manager, per ogni account che può entrare nella bacheca. Se la password non si indovina e non è mai stata usata altrove, brute force e credential stuffing perdono quasi tutta la loro efficacia.
Sul fronte del core ci sono due novità che nel 2012 non esistevano. Da WordPress 6.8 le password degli utenti sono salvate nel database con bcrypt al posto del vecchio phpass, e la conversione avviene in automatico al primo login successivo all’aggiornamento o al primo cambio password, senza che tu debba fare nulla; non rende più difficile indovinarla dal form, ma rende molto più costoso craccarla da una copia rubata del database.
La seconda novità sono le application password, introdotte in WordPress 5.6: sono credenziali generate dal profilo utente, pensate per le integrazioni via REST API e, dove è attivo, XML-RPC, che non possono essere usate per entrare da wp-login.php e che si possono revocare una per una. Così, quando colleghi un’app o un’automazione, non consegni la password principale di un amministratore e, se un’integrazione viene compromessa, la spegni senza toccare il resto.
Due fattori e passkey: lo stato dell’arte a ottobre 2026
L’autenticazione a due fattori resta la misura con il miglior rapporto tra sforzo e risultato, perché anche una password indovinata o rubata non basta più per entrare. È bene sapere che, a ottobre 2026, il core di WordPress non integra né la 2FA né le passkey: nemmeno WordPress 7.1 le ha portate nel core, quindi si passa da un plugin. La scelta che consiglio come punto di partenza è Two Factor, il plugin mantenuto dalla comunità dei contributori del core, che supporta app di autenticazione TOTP, codici via email e codici di backup.
Le passkey sono il passo successivo, perché sostituiscono il segreto da ricordare con una chiave crittografica legata al dispositivo e al dominio, e per questo resistono anche al phishing; la stessa documentazione ufficiale sul brute force di WordPress le cita tra le difese consigliate. Per aggiungerle oggi servono plugin dedicati, come il componente Two-Factor Provider: WebAuthn, che si appoggia a Two Factor e supporta Windows Hello, Touch ID e chiavi hardware; prima di installarlo controlla però la compatibilità dichiarata con la tua versione di WordPress, perché al momento in cui scrivo la scheda sul repository indica test fino alla 6.9 e non ancora sulla 7.x.
La sicurezza del login non è una porta blindata, è una serie di porte normali messe una dietro l’altra: ognuna da sola si può forzare, tutte insieme fanno perdere la pazienza a chiunque.
Limitare i tentativi: dal bordo al server
Limitare i tentativi significa contare gli accessi falliti o le richieste verso il login e bloccare temporaneamente chi esagera; WordPress non lo fa da solo, quindi va aggiunto. Il punto chiave, che la guida ufficiale di WordPress sul brute force sottolinea con chiarezza, è che conviene farlo il più lontano possibile da PHP: a livello di CDN o WAF, oppure nel web server, perché ogni richiesta fermata prima di WordPress è una richiesta che non consuma CPU e connessioni al database.
Al bordo: WAF e CDN
Se il sito passa da una CDN con firewall applicativo, come Cloudflare, la regola di rate limiting sul percorso del login è la prima cosa da configurare: anche il piano gratuito di Cloudflare include una regola di rate limiting, con conteggio per IP e finestra breve, che è già sufficiente per proteggere wp-login.php, mentre i piani superiori permettono condizioni più ricche. Ne parlo più in dettaglio nell’articolo sulle CDN per WordPress, dove trovi anche le accortezze per non bloccare i crawler buoni mentre fermi quelli cattivi.
Nel web server: nginx e Apache
Se gestisci tu il server, nginx offre un rate limiting nativo molto efficace; questo è l’esempio proposto dalla documentazione di WordPress, che applica la stessa zona sia al login sia a XML-RPC:
limit_req_zone $binary_remote_addr zone=logins:10m rate=10r/m;
server {
location = /wp-login.php {
limit_req zone=logins burst=20 nodelay;
include fastcgi_params;
}
location = /xmlrpc.php {
limit_req zone=logins burst=20 nodelay;
include fastcgi_params;
}
}Su Apache e LiteSpeed, che leggono il file .htaccess, la regola più robusta resta quella che apre il login solo a indirizzi noti, utile quando chi amministra il sito lavora da una sede con IP statico o da una VPN; nota la sintassi di Apache 2.4 con Require, che sostituisce i vecchi Order e Allow che usavo nel 2012:
# wp-login.php raggiungibile solo dagli IP indicati
<Files "wp-login.php">
Require ip 203.0.113.15 203.0.113.16
</Files>Nel sito: un plugin di limitazione
Quando non controlli né il server né una CDN, un plugin come Limit Login Attempts Reloaded resta una soluzione valida e leggera, che protegge anche XML-RPC e il login di WooCommerce; è l’erede del Simple Login Lockdown che usavo nel 2012, ma oggi va considerato l’ultima rete di sicurezza e non la prima.
XML-RPC: chiuderlo o domarlo
xmlrpc.php è l’endpoint del vecchio protocollo XML-RPC, ancora presente nel core per compatibilità, ed è uno dei bersagli preferiti dei brute force perché il metodo system.multicall consente di provare molte password con una sola richiesta HTTP, aggirando i limitatori più ingenui. Se non lo usi, e con il REST API capita sempre più spesso, la scelta più semplice è chiuderlo nel server.
# .htaccess: blocca del tutto l'accesso a xmlrpc.php
<Files "xmlrpc.php">
Require all denied
</Files>Prima di farlo verifica però che nessuno ne abbia bisogno: alcune funzioni di Jetpack, vecchie app mobili e alcuni strumenti di pubblicazione esterni lo usano ancora, e in quei casi la documentazione ufficiale consiglia di limitarlo con regole WAF e di applicare un rate limiting aggressivo invece di spegnerlo. Attenzione infine a un equivoco molto diffuso: il filtro xmlrpc_enabled, nonostante il nome, disattiva soltanto i metodi che richiedono autenticazione e lascia attivi i pingback, quindi va benissimo per togliere di mezzo i tentativi di login via XML-RPC, ma non spegne l’endpoint.
<?php
// Disattiva i metodi XML-RPC che richiedono autenticazione
// (i pingback restano attivi: per chiudere tutto meglio agire sul server).
add_filter( 'xmlrpc_enabled', '__return_false' );Cosa non serve (più): nascondere wp-admin
Nascondere wp-admin o rinominare l’indirizzo del login non è una difesa: riduce il rumore nei log, ma non protegge un account con una password debole, e se diventa l’unica misura dà un falso senso di sicurezza. Lo dico con una certa autoironia, visto che l’articolo originale era proprio uno snippet per nascondere il login, ma la stessa guida ufficiale di WordPress oggi classifica tra le pratiche superate le riscritture .htaccess pesanti, le liste di blocco per nazione e la protezione con BasicAuth di tutta la cartella /wp-admin.
Ci sono poi abitudini innocue ma sopravvalutate, che vedo ancora nelle checklist copiate da un sito all’altro:
- Evitare l’utente «admin»: è buona norma, ma i nomi utente si scoprono facilmente, quindi è un dettaglio e non una protezione.
- Bloccare gli IP a mano: con attacchi distribuiti su migliaia di indirizzi è una corsa persa in partenza, mentre il rate limiting automatico fa lo stesso lavoro senza che tu debba stare di guardia.
- Installare tre plugin di sicurezza insieme: si pestano i piedi, duplicano i controlli e spesso rallentano proprio la pagina di login; meglio uno solo, scelto bene, più le regole al bordo.
Quello che funziona davvero è noioso ma solido: aggiornamenti puntuali, pochi amministratori, backup verificati e un’occhiata periodica ai log. Su WordPress e sulla sua evoluzione recente, compreso il passaggio alla versione 7.0 con l’AI nativa, trovi altri approfondimenti nella categoria WordPress del blog.
Tirando le somme
Riassumendo, proteggere il login di WordPress nel 2026 significa costruire pochi strati semplici e ben configurati: password lunghe e uniche gestite da un password manager, application password per tutte le integrazioni, due fattori per ogni amministratore e, se puoi, passkey; rate limiting il più vicino possibile al bordo, XML-RPC chiuso o limitato, e un plugin di limitazione dei tentativi solo come ultima rete. Nascondere il login può restare un vezzo per tenere puliti i log, ma non deve mai essere la difesa principale.
Se vuoi approfondire, ti consiglio di partire dalla documentazione ufficiale sul brute force e da quella sulle application password, e di dare un’occhiata anche all’articolo dedicato ai bot aggressivi e al rate limiting, che affronta lo stesso problema dal punto di vista della banda. Raccontami nei commenti quante richieste vedi arrivare su wp-login.php, e se l’articolo ti è stato utile condividilo con chi conta ancora sul fatto che nessuno conosca l’indirizzo della sua pagina di login.
E se preferisci non fare tutto da solo, puoi dare un’occhiata a come lavoro come consulente WordPress, prenotare una call conoscitiva gratuita oppure scrivermi passando dalla pagina dei contatti: ne parliamo con calma, partendo dal tuo sito e non da una checklist generica.



Ma la bella patata a che serve solo ad attirare traffico?
Ma fai il serio scusa è
Lo snippet funziona anche troppo bene, quello che non riesco a capire e come far sì che io possa accedere alla url di login, grazie alla Key. Devo scrivere la stringa in maniera particolare nel browser?
@ASD, funzione prettamente “ornamentale” 😀
@MAR
teoricamente in un’installazione standard dovresti accedere con una url del genere:
http://www.nomesito.com/wp-login.php?hide_in_key=12345&redirect_to=/wp-admin/
(dove 12345 è la nostra chiave)
nel tempo penso di aver migliorato questo script è qui ne trovi una versione più aggiornata: https://gist.github.com/3003290
qui anche alcune slide in cui ho parlato di questa tecnica: https://maurizio.mavida.com/2012/11/26/wordpress-hardening/
Grazie, testerò nei prossimi giorni 🙂
Ciao,
inizio con il rigraziarti per il tuo condividere e ti faccio i miei complimenti per il tuo creare…
Sto provando questa tecnica ma non capisco dove sbaglio, funziona tutto, ossia viene bloccato l’accesso a wp-admin e wp-login ma non a login ho tenuto conto del tuo aggiornamento sto usando “.htaccess | vanillia installation” limitato a questa sola parte.
Hai qualche prezioso consiglio da darmi :-)?
Ok ho capito! Grazie al tuo video
http://youtu.be/LtksvHORoNg
perdona la mia sterminata ignoranza 🙂
Grazie ancora!
Ciao Maurizio,
complimenti per l’articolo! Ti chiedo solo una cosa: per facilitare l’accesso agli “utenti” cosa ne pensi di sistemi di login con autenticazione tipo Clef?
In generale sono assolutamente a favore dell’autenticazione a due fattori ma non lo vedo applicabile a tutte le realtà sopratutto in considerazione del livello medio degli utenti.
Ciao Maurizio,
ho provato a modificare il mio file .htaccess con il tuo snippet. Dopo i primi minuti in cui tutto sembrava funzionare alla grande il server ha cominciato a restituirmi un errore 500. Ho risolto inserendo un file .htaccess “vuoto”. Non ho assolutamente capito il motivo dell’errore e del perché non si è presentato subito. Per onestà devo dirti che sono autodidatta del mondo internet e ci sono ancora parecchie cose che devo imparare. Grazie in anticipo.
Ciao Enrico,
per aiutarti dovrei vedere cosa hai scritto nel tuo htaccess (magari tramite screenshot)
potrebbe anche essere solo un problema di sintassi dovuto ad un copia ed incolla sbagliati o ad una sostituzione sbagliata dei valori tra le parentesi quadre.
infine come ultimo consiglio prova ad eliminare una riga alla volta per capire quale genera il problema
Ciao, mi sono imbattuto in questo articolo ed è stato amore a prima vista, la sicurezza del login passando solo per l’.htaccess senza plugin senza parole… sono andato a cercare il file su github, e pi iol tuo intervento al wordcamp di Bologna su youtube (mitico FTP Brutto)…
Mi chiedevo, visto le date di pubblicazione, il tutto è ancora valido è “sicuro”? e poi visto la mia non eccelsa dimistichezza con codici e affini la “loginkey=12345g&redirect” (che ho ovviamente cambiato) a cosa serve? io ho personalizzato il login e ci vado direttamente digitando cicciologin, ma la key non mi viene mai chiesta e se scrivo wp-admin mi riindirizza alla home, sbaglio qualcosa?
Scusa se ti ho tempestato di domande, grazie del tuo lavoro e delle risposte (se vorrai darmele)
la loginkey (che devi cambiare due volte sia alla riga 5 che alla riga 11) serve solo come chiave per verificare che l’utente sia passato dal link corretto.
il redirect che viene effettuato in modo trasparente dall’htaccess reindirizza con la chiave ma se arrivo su wp-login senza quella chiave (accesso diretto) vengo ributtato in home…
continua però ad esserci una stranezza se vado a “cicciologin” mi indirizza correttamtente se cambio o tolgo un carattere per esempio cicciologn mi rimanda all’hone ma se scrivo qualsiasi cosa dopo ciccilogin che sò cicciologinvattelapesca mi indirizza al wp-admin …
come mai?