Codificare le entità HTML

Incolla del testo e riprendilo con i caratteri che cambiano il modo in cui un documento viene analizzato sostituiti dalle loro forme protette. È il passo che trasforma il testo scritto da qualcun altro in contenuto invece che in struttura, ed è il punto in cui una sostituzione dimenticata trasforma un campo commenti in un problema di sicurezza. Il conto avviene in questa pagina.

La prima è quello che fa un motore di template. La seconda è per una catena di elaborazione che non tratta bene l’UTF-8.

Risultato

La risposta compare qui mentre scrivi.

  • Dove gira

    Non viene caricato nulla, perché non c’è nessun file: il calcolo avviene in questa pagina.

  • Nessuna coda, nessun account

    Risponde alla velocità della tua macchina e non chiede mai chi sei.

  • Tutte le volte che vuoi

    Non si conta né si limita nulla: rispondere di nuovo non ci costa niente.

Come funziona

  1. Incolla il testo o il frammento di markup.
  2. Scegli fin dove proteggere: solo ciò che cambia l’analisi, oppure anche tutto ciò che va oltre l’ASCII.
  3. Copia il risultato. Non è uscito dalla tua macchina.

I cinque caratteri di cui si tratta

Sono `<`, `>`, `&` e le due specie di virgolette. Il minore apre un tag, il maggiore lo chiude, la e commerciale apre un riferimento di carattere, e le virgolette chiudono il valore di un attributo. Tutto il resto del repertorio non cambia in nessun modo come un documento viene analizzato.

La brevità della lista è la ragione per cui la protezione minima è quella giusta quasi sempre: proteggere solo cinque caratteri lascia il testo leggibile nel sorgente, che è utile a chiunque lo debba guardare in seguito. Proteggere tutto produce un documento corretto e illeggibile, e la leggibilità del sorgente non è un vezzo quando qualcuno dovrà rileggerlo per capire un difetto.

La e commerciale va per prima, o non va

L’ordine delle sostituzioni non è indifferente. Se sostituisci il minore prima della e commerciale, la `&` che hai appena introdotto in `&lt;` viene protetta a sua volta e diventa `&amp;lt;`: nel documento finale compare la scritta `&lt;` invece del carattere.

È l’errore classico di ogni funzione di protezione scritta a mano, e si riconosce dalla forma del risultato — un `&amp;` seguito da un nome di entità. Qui le sostituzioni avvengono in un passaggio solo, il che rende l’ordine irrilevante per costruzione, che è il modo giusto di non doversene ricordare.

Contenuto e attributo non sono la stessa cosa

Dentro il testo di un elemento bastano `<` e `&`. Dentro il valore di un attributo servono anche le virgolette, perché quelle chiudono il valore in anticipo e tutto ciò che segue diventa un altro attributo — che è esattamente il modo in cui si inserisce un `onerror` in un tag che non doveva averne.

Peggio ancora è un attributo senza virgolette, dove basta uno spazio a terminare il valore. Questa pagina protegge entrambe le specie di virgolette proprio perché il testo che esce da qui può finire in tutti e due i posti, e la protezione più prudente è l’unica che regga senza sapere dove andrà.

Quando serve «tutto oltre l’ASCII»

In un documento HTML dichiarato come UTF-8 — cioè in tutto ciò che si scrive oggi — le lettere accentate non hanno nessun bisogno di essere protette. `città` funziona così com’è, e trasformarlo in `citt&agrave;` non aggiunge niente se non rumore.

La seconda modalità esiste per un caso preciso: una catena di elaborazione che non tratta bene l’UTF-8. Un vecchio sistema di posta, un generatore di PDF, un endpoint che dichiara Latin-1, un campo di database con una codifica ereditata. Lì scrivere tutto in ASCII puro con entità numeriche è l’unico modo per far arrivare una `à` intatta dall’altra parte.

Proteggere è igiene di uscita, non un filtro

La protezione va fatta quando il dato esce, cioè nel momento in cui viene inserito in un documento, e non quando entra. Un dato ripulito all’ingresso è un dato modificato per sempre, e va bene finché non serve mostrarlo in un contesto diverso — un file CSV, una email di testo semplice, una risposta JSON — dove quelle entità diventano rumore visibile.

La differenza pratica è che il valore giusto da conservare è quello che la persona ha scritto. Un utente che si chiama `D&Agrave;` in un database ha subito un difetto, non una protezione, ed è il tipo di guasto che si scopre anni dopo quando qualcuno esporta i dati verso un altro sistema.

Tre modi di scrivere lo stesso carattere

Un riferimento di carattere può avere un nome — `&amp;` —, una forma decimale — `&#38;` — o una esadecimale — `&#x26;`. Sono equivalenti per qualunque parser HTML, e la scelta è di leggibilità: i nomi si leggono, i numeri funzionano anche dove il nome non esiste.

I nomi però non sono universali fuori dall’HTML. In XML ne esistono cinque soltanto, quindi un `&nbsp;` scritto dentro un documento XML o dentro un feed RSS rigoroso è un errore di sintassi e non uno spazio: lì serve la forma numerica, `&#160;`. È una delle differenze che spiegano perché un frammento copiato da una pagina web rompa un feed.

Perché qui trovi &#39; e non &apos;

Per l’apostrofo dritto questa pagina produce il riferimento numerico `&#39;` invece del nome `&apos;`. Il motivo è compatibilità: `&apos;` è definito in XHTML e in XML, e non faceva parte dell’HTML 4. I browser moderni lo capiscono tutti, ma il testo che esce da qui può finire in un feed, in un template o in un parser che non è un browser.

La forma numerica non ha quel problema in nessun contesto, perché il numero è il punto di codice e non un nome da cercare in una tabella. È la stessa logica per cui un codificatore prudente preferisce `&#39;` ovunque: costa quattro caratteri in più e toglie una categoria intera di sorprese.

Proteggere l’HTML non salva JavaScript

La protezione delle entità vale nel contesto HTML e non altrove. Un valore inserito dentro un blocco `<script>`, dentro un attributo `href` che comincia per `javascript:` o dentro un pezzo di CSS obbedisce ad altre regole di analisi, e le entità lì non fanno niente di utile.

Ogni contesto ha la sua protezione, e questa pagina ne fa una sola. Se stai costruendo un documento a mano invece di usare un motore di template, quella è la decisione da rivedere per prima: i template moderni proteggono in automatico e sanno in che contesto stanno scrivendo, mentre una concatenazione di stringhe non lo sa e non lo può sapere.

Il commento di un utente è un dato di un utente

Quello che si porta a un codificatore di entità è quasi sempre testo scritto da qualcun altro: un commento, una recensione, la descrizione di un prodotto, un messaggio di assistenza. Sono contenuti di persone, e su un servizio remoto sarebbero una comunicazione di dati a un terzo senza alcuna necessità.

Qui la sostituzione avviene nella scheda, quindi il testo non ci arriva e non compare in nessun log. Nel senso del GDPR non c’è niente da giustificare per il contenuto del campo: quello che resta è la visita alla pagina, che è scritta nell’informativa e riguarda te e non le persone di cui stai maneggiando le parole.

Codificare le entità HTML: domande frequenti

Il mio testo viene mandato a un server?

No. La sostituzione avviene in questa pagina mentre digiti e non parte nessuna richiesta con il contenuto. Conta perché quello che si protegge è quasi sempre testo scritto da altre persone: commenti, recensioni, messaggi di assistenza.

Perché i miei accenti non vengono protetti?

Perché in un documento UTF-8 non ne hanno bisogno: una à non cambia in nessun modo il modo in cui il documento viene analizzato. La seconda modalità li protegge lo stesso, e serve solo quando il testo deve attraversare qualcosa che non tratta bene l’UTF-8, come un vecchio generatore di PDF o un endpoint dichiarato Latin-1.

Questo mi protegge dall’XSS?

È il pezzo giusto nel posto giusto, ma da solo non basta. La protezione delle entità vale nel contesto HTML: dentro un blocco script, dentro un href che comincia per javascript: o dentro il CSS valgono altre regole. La difesa vera è un motore di template che sappia in che contesto sta scrivendo, più una policy di sicurezza dei contenuti.

Perché nel risultato vedo &amp;lt;?

Perché il testo era già protetto una volta e lo hai protetto di nuovo. La e commerciale di `<` è diventata `&`, quindi nella pagina finale si legge la scritta `<` invece del carattere. Decodifica una volta e ricodifica una sola, oppure trova il punto in cui il template protegge un valore già protetto.

C’è un limite di lunghezza?

Solo quello della tua macchina. Non c’è nessun server che faccia il lavoro, quindi non c’è niente da contare né da razionare: un testo molto grande fa pensare la scheda per un momento, e quello è tutto.

Altri strumenti