La sigla XSS viene dall’inglese cross-site scripting; si scrive X invece di C per evitare la confusione con i fogli di stile CSS. È una vulnerabilità di tipo injection: il sito inserisce nella pagina un dato proveniente dall’esterno senza neutralizzarlo, e il browser lo interpreta come codice. Il MITRE la cataloga con l’identificativo CWE-79. Poiché lo script sembra provenire dal sito stesso, il browser gli concede la stessa fiducia che al resto della pagina.
Come funziona un attacco XSS
Tutto parte da un valore controllato dall’attaccante: un parametro dell’indirizzo, un campo di un modulo, un commento, un header HTTP registrato nelle statistiche. Se il codice mostra questo valore così com’è, una stringa come <script>…</script> o un attributo onerror="…" diventa eseguibile. Lo script può allora leggere il contenuto della pagina, inviare richieste a nome della persona connessa, modificare ciò che vede o reindirizzarla verso un altro sito.

Su un sito WordPress, il bersaglio preferito è l’amministratore. Uno script eseguito nella sua sessione può creare un account, installare un plugin o cambiare un’impostazione, senza mai conoscere la sua password: è il browser stesso a inviare i cookie di login con ogni richiesta.
I diversi tipi di XSS
- XSS memorizzata (persistente): lo script viene salvato lato server, per esempio nel database, e poi restituito a ogni visualizzazione. Alla vittima non è richiesta alcuna azione particolare, le basta aprire la pagina.
- XSS riflessa: lo script viaggia nella richiesta, spesso un link trappola, e il server lo ricopia subito nella risposta. La vittima deve cliccare.
- XSS basata sul DOM: è il JavaScript della pagina a inserire un dato non affidabile, come il frammento di un indirizzo. Il server può non vedere passare nulla.
OWASP descrive anche la XSS «cieca» (blind XSS): una variante memorizzata che scatta più tardi, in un’interfaccia che l’attaccante non vede. È proprio il caso di log, statistiche e moduli ricevuti consultati dalla Bacheca. Gli esempi reali di XSS in plugin popolari mostrano che questo scenario non ha nulla di teorico.
Per WordPress: fare l’escaping all’ultimo momento
La documentazione per sviluppatori di WordPress fissa una regola semplice: fare l’escaping il più tardi possibile, nel momento in cui il dato viene mostrato, con la funzione che corrisponde al contesto.
| Contesto di visualizzazione | Funzione |
|---|---|
| Testo dentro un elemento HTML | esc_html() |
| Valore di un attributo | esc_attr() |
| Indirizzo in href o src | esc_url() |
| JavaScript inline | esc_js() |
| Contenuto di una textarea | esc_textarea() |
| HTML in cui alcuni tag sono ammessi | wp_kses(), wp_kses_post() |
<h2><?php echo esc_html( $titolo ); ?></h2>
<a href="<?php echo esc_url( $link ); ?>" title="<?php echo esc_attr( $info ); ?>">Vedi</a>
Validare e sanificare gli input resta utile, ma non sostituisce questo escaping in uscita: uno stesso valore può essere mostrato in più contesti.
Come proteggersi senza toccare il codice
- Aggiornare in fretta plugin e temi: le XSS sfruttate in massa colpiscono quasi sempre versioni già corrette.
- Tenere pochi account con privilegi ed eliminare quelli che non servono più.
- Sorvegliare la comparsa di nuovi amministratori, segnale frequente di una XSS sfruttata.
- Aggiungere una Content Security Policy, sapendo che una versione rigida, che vieta gli script inline, è difficile da mantenere con WordPress. La nostra guida agli header di sicurezza HTTP per WordPress descrive le opzioni.
- Un firewall applicativo può fermare payload noti, senza garanzie contro una variante inedita.
WP Masquerade Pro invia degli header di sicurezza, tra cui, come opzione, una CSP di base. Questa CSP non limita gli script: non blocca quindi una XSS. WP Masquerade non è né un firewall applicativo né uno strumento che corregge il codice: solo l’aggiornamento del componente difettoso chiude la vulnerabilità.
Errori frequenti
- Confondere XSS e CSRF: la seconda fa inviare al browser una richiesta contraffatta, senza eseguire script nella pagina. Una XSS, invece, permette di aggirare le protezioni anti-CSRF, perché lo script legge i token della pagina.
- Credere che un dato sia «interno» perché viene mostrato nell’amministrazione: un header HTTP o un indirizzo visitato arrivano dall’esterno.
- Usare
esc_html()in un attributo oesc_attr()per un indirizzo: ogni contesto ha la sua funzione. - Pensare che la protezione contro la SQL injection basti: un dato salvato correttamente nel database può restare pericoloso al momento della visualizzazione.