WP Alarm: come ho costruito un sistema centralizzato per monitorare la sicurezza di più siti WordPress
Per un po’ ho gestito la sicurezza dei miei siti WordPress come fanno in molti: plugin di sicurezza su ogni installazione, email di notifica configurate, accessi manuali periodici per controllare i log. Funziona, in un certo senso. Ma quando gestisci più siti, ti ritrovi a controllare inbox diverse, dashboard diverse, e a chiederti se c’è qualcosa che ti stai perdendo su un sito a cui non hai guardato da qualche giorno.
Il problema non è che gli strumenti mancano. È che ognuno parla solo di sé stesso. Nessun punto di controllo unico.
Il vero rischio: arrivare tardi
Un tentativo di accesso fallito su un sito è rumore di fondo. Cento tentativi in dieci minuti sullo stesso account sono un attacco. La differenza tra saperlo subito e saperlo il giorno dopo può essere la differenza tra bloccare l’attacco e trovare il sito compromesso.
Con log sparsi su più installazioni, quella visibilità in tempo reale semplicemente non esiste. Ho deciso di costruirmela.
L’architettura: hub-and-spoke
L’idea centrale è separare chi segnala da chi raccoglie. Ho costruito due plugin distinti che lavorano insieme:
WP Alarm Messenger si installa su ogni sito da monitorare. Il suo unico compito è intercettare eventi di sicurezza rilevanti e trasmetterli all’hub centrale via REST API.
WP Alarm Hub un sito WordPress dedicato che fa solo da centro di raccolta. Riceve i messaggi in arrivo, li archivia in una tabella dedicata e li presenta in un’unica interfaccia amministrativa.
Ho scelto due plugin separati invece di uno solo per una ragione precisa: il Messenger deve essere il più leggero possibile. Nessuna UI, nessun overhead, solo cattura e trasmissione. L’Hub può essere più pesante perché gira su un sito dedicato, non su ogni installazione monitorata.
Cosa viene monitorato
Il sistema traccia tre categorie di eventi:
- Accessi falliti username e IP a ogni tentativo non riuscito
- Blocchi IP quando un plugin di sicurezza come Wordfence blocca un indirizzo
- Nuovi utenti creazione di account, inclusi quelli non autorizzati
Ogni evento viene trasmesso all’hub con un payload strutturato: nome del sito, tipo di evento, timestamp, dettagli specifici.
Le sfide tecniche che non sembrano tali finché non ci sbatti contro
Deduplicazione degli eventi. Un attacco brute force può generare decine di tentativi al minuto. Se ogni fallito login genera una chiamata REST verso l’hub, si crea un flood inutile. Ho risolto con un sistema di transient WordPress: il Messenger memorizza un hash dell’evento e non lo ritrasmette se lo stesso evento si è già verificato negli ultimi cinque minuti. L’hub riceve segnali significativi, non rumore.
Autenticazione tra plugin. Come fa l’Hub a fidarsi dei messaggi in arrivo? Ogni Messenger è configurato con una chiave condivisa che viene inclusa in ogni richiesta REST. L’Hub verifica la chiave prima di accettare il payload. È una soluzione pragmatica più robusta dell’assenza di autenticazione, meno complessa di un sistema nonce con scadenza (che è tra i miglioramenti pianificati).
Affidabilità della trasmissione. Se l’Hub non è raggiungibile nel momento in cui il Messenger tenta di inviare un evento, l’evento va perso. Per ora il sistema logga l’errore di invio localmente, ma non c’è una coda con retry automatico. È una limitazione consapevole tenerla a mente aiuta a contestualizzare il livello di affidabilità attuale: ottimo per un early warning system, non sufficiente per un sistema mission-critical.