Uma entidade HTML é uma forma de escrever um caractere para que o navegador o exiba como texto em vez de interpretá-lo como marcação. Digite um < cru no seu conteúdo e o navegador começa a ler uma tag; escreva < no lugar e ele renderiza um < literal na página. Essa troca é a ideia por trás de toda a codificação de entidades HTML.
Cinco caracteres carregam significado especial em HTML e são os que você mais escapa: <, >, &, " e '. Você os escapa por dois motivos. O primeiro é exibição: você quer mostrar código ou marcação como texto. O segundo, e mais importante, é segurança: escapar entrada não confiável é a base para barrar o cross-site scripting (XSS).
Existem três formas intercambiáveis de escrever qualquer entidade — nomeada (<), decimal (<) e hexadecimal (<) — e todas resolvem para o mesmo caractere. A parte difícil é quando escapar e com o quê, porque a resposta certa depende de onde o valor cai: texto HTML, um atributo, um script ou uma URL. Abaixo estão as notações, o conjunto reservado, uma matriz de decisão por contexto e as armadilhas mais comuns.
O que é uma entidade HTML? (anatomia)
Uma entidade HTML, também chamada de referência de caractere, é um código curto que substitui um único caractere. Toda entidade começa com um e-comercial & e termina com um ponto e vírgula ;. O que fica entre eles determina qual caractere você obtém.
Existem três formatos:
&name;— uma referência nomeada, como<ou©.&#decimal;— uma referência numérica decimal, como<.&#xhex;— uma referência numérica hexadecimal, como<.
O navegador lê a referência, consulta o caractere para o qual ela aponta e renderiza esse único caractere. Nada no resultado visível muda — < e um < cru aparecem de forma idêntica. A única diferença é que a entidade é tratada como texto, nunca como o início de uma tag.
As três notações: nomeada, decimal, hexadecimal
As três notações referenciam o mesmo ponto de código Unicode; diferem apenas na grafia. Uma entidade nomeada é a forma legível, mas só existe para caracteres que têm um nome definido. Uma entidade decimal escreve o ponto de código na base 10. Uma entidade hexadecimal escreve o mesmo ponto de código na base 16, que mapeia diretamente para a notação U+XXXX que você vê no padrão Unicode.
| Caractere | Nomeada | Decimal | Hex |
|---|---|---|---|
< | < | < | < |
& | & | & | & |
© | © | © | © |
é | é | é | é |
Como o hex espelha U+XXXX diretamente — é é U+00E9, logo é — muitos desenvolvedores recorrem a ele ao documentar ou raciocinar sobre um ponto de código específico. Para marcação do dia a dia, as entidades nomeadas se leem melhor.
Os cinco caracteres reservados que você deve escapar
Estes são os caracteres especiais de HTML que alteram como o navegador analisa um documento. Se um deles aparece em conteúdo que deveria ser exibido em vez de executado, escape-o.
| Caractere | Nomeada | Decimal | Hex | O que quebra se você não escapar |
|---|---|---|---|---|
< | < | < | < | Inicia uma tag — o navegador lê o texto seguinte como marcação |
> | > | > | > | Fecha uma tag prematuramente |
& | & | & | & | Inicia uma entidade — o resto pode ser mal interpretado como referência |
" | " | " | " | Encerra cedo demais o valor de um atributo entre aspas duplas |
' | ' | ' | ' | Encerra cedo demais o valor de um atributo entre aspas simples |
A entidade do e-comercial HTML é a raiz de todo o sistema. O caractere & começa toda entidade, então ele precisa ser escapado primeiro: escape os sinais de menor/maior antes do e-comercial e você acaba reescapando o & nas entidades que produziu. A seção de armadilhas detalha esse caso.
Quando você realmente precisa escapar? (sensível ao contexto)
É aqui que aparece a maioria dos bugs e das vulnerabilidades. A regra é: escape no momento da saída, ajustado ao contexto em que o valor cai. Um valor seguro em um lugar é perigoso em outro, então a codificação que você aplica tem de combinar com o destino.
Conteúdo de elemento HTML
Quando você solta um valor entre tags — dentro de um <p>, um <div>, um <td> — escape <, > e &. Escapar as aspas aqui é inofensivo, mas desnecessário. Se você quer mostrar o texto <strong> como caracteres literais em vez de deixar a próxima palavra em negrito, codifique-o para <strong> e o navegador imprime a tag em vez de aplicá-la.
Valores de atributos HTML
Dentro de um atributo, os caracteres de aspas se tornam críticos. Se um valor fica em title="…" e contém um " não escapado, ele encerra o atributo cedo demais e permite que um atacante acrescente novos atributos — um vetor clássico de XSS. Escape " (e, idealmente, ') no contexto de atributo. Um valor como He said "hi" precisa virar He said "hi" para permanecer contido.
Dentro de <script> ou JavaScript inline
As entidades HTML não ajudam aqui. Uma string montada dentro de um bloco <script> ou de um manipulador de evento inline precisa de escape de string JavaScript ou JSON, não de referências de caractere. Escrever " dentro de um literal de string JS produz os seis caracteres literais, não uma aspa. Para esse contexto, use a ferramenta Escape JSON e leia o guia completo de escape de strings JSON para as regras de \uXXXX que de fato valem dentro de um script.
Dentro de uma URL
Uma URL tem seu próprio esquema de escape: a codificação por porcentagem. As entidades HTML não tornam um valor seguro para URL. A string a&b c cabe numa query como a%26b%20c, não como a&b c — o espaço ainda quebra a URL, e o & ainda separa parâmetros. Use o Codificador / Decodificador de URL para isso, e o guia de codificação e decodificação de URL para as regras completas sobre caracteres reservados versus não reservados.
A matriz de decisão
| Contexto | Escape com | Exemplo | Escolha errada que falha |
|---|---|---|---|
| Conteúdo de elemento HTML | Entidades HTML (< > &) | <strong> → <strong> | Deixar < cru injeta uma tag |
| Valor de atributo HTML | Entidades HTML (" ' críticos) | "hi" → "hi" | Um " não escapado escapa do atributo |
<script> / JS inline | Escape de string JS / JSON | " → \" | Entidades HTML são inertes em JS |
| URL / query string | Codificação por porcentagem | espaço → %20 | & e entidades ainda quebram a URL |
Nomeadas vs. numéricas: qual usar?
As entidades nomeadas são legíveis e o padrão certo para os caracteres reservados comuns e os símbolos conhecidos — <, &, ©, —. Elas, porém, só existem para caracteres que têm um nome definido. As entidades numéricas, decimais ou hexadecimais, conseguem codificar qualquer ponto de código, inclusive os que não têm nome, o que as torna o recurso universal de reserva. Quando você não pode garantir que o sistema consumidor suporta uma determinada entidade nomeada, a numérica é a escolha segura.
Por que o apóstrofo é ' e não '
A entidade nomeada ' só foi introduzida no HTML5 e no XML. Ela é indefinida no HTML4, então alguns parsers antigos e clientes de e-mail a renderizam como o texto literal ' em vez de um apóstrofo. A referência numérica ' — e sua gêmea decimal ' — aponta para exatamente o mesmo caractere, U+0027, e é entendida por todo parser conforme já escrito. Bibliotecas de escape bem testadas, como a he, emitem ' para a aspa simples exatamente por esse motivo, e um bom codificador segue essa convenção para que a saída possa ser inserida com segurança em qualquer contexto HTML, XML ou de atributo.
Charset vs. entidades: quando codificar não-ASCII
Um conjunto de caracteres, como UTF-8, decide como os caracteres são armazenados em bytes. Uma entidade é uma forma de soletrar um caractere usando apenas ASCII puro (&, #, ;, letras, dígitos). São camadas diferentes, e confundi-las leva a codificação desnecessária.
Numa página UTF-8 — ou seja, quase toda página moderna que declara <meta charset="utf-8"> — letras acentuadas, traços e emoji são caracteres crus válidos. Deixe é, — e 😀 exatamente como estão. Codificar tudo em entidades só importa quando o texto precisa sobreviver a um charset legado de byte único ou a um sistema que estraga UTF-8 cru; existe um modo “codificar tudo que não for ASCII” para esses casos. Se você não tem certeza de como bytes, pontos de código e caracteres se relacionam, o guia de codificação UTF-8, UTF-16 e Unicode apresenta o modelo.
Armadilhas comuns com entidades HTML
Escapar o & por último causa escape duplo
A ordem importa. Se você substitui < e > antes do &, as entidades que acabou de criar (<, >) também têm seu & inicial escapado, então < acaba virando &lt; e renderiza como o texto literal <. Sempre escape o & primeiro e depois o resto. Essa única regra evita o bug de codificação mais comum que existe.
Codificar duas vezes um texto já escapado
Passar de novo por um codificador um texto que já está escapado o recodifica. & vira &amp;, e o visitante vê & na página em vez de &. Escape exatamente uma vez, no momento da saída. Se um valor passa por várias camadas, garanta que só uma delas escapa.
Mojibake na decodificação
O caminho inverso tem sua própria cilada. Decodifique com o charset errado, ou decodifique duas vezes, e você obtém saída embaralhada — o clássico mojibake. Se uma página está mostrando um &lt; literal onde você esperava <, cole-o no Decodificador de Entidades HTML para ver exatamente para que as entidades resolvem; ele lida com nomeadas, decimais, hex e até referências legadas sem terminação como © sem o ponto e vírgula final.
Confiar no escape como cura completa para XSS
O escape é a primeira linha de defesa, não a única. Como o HTML tem vários contextos com regras diferentes, escapar para o contexto errado deixa um buraco: aspas em atributos, escape JS em script, codificação por porcentagem em URLs. Combine o escape correto e sensível ao contexto com uma Content Security Policy e o auto-escape do seu framework, que cobrem o que o escape de entidades sozinho não pega.
Como codificar e decodificar entidades na prática
Quando você monta HTML à mão, escapa você mesmo. Aqui está um escapeHtml() correto que cuida da ordem com o & primeiro, além da prática melhor para código real de aplicação.
// Os cinco caracteres reservados e suas entidades seguras:
// < → < > → > & → & " → " ' → '
function escapeHtml(str) {
return str
.replace(/&/g, '&') // & PRIMEIRO, para que as entidades seguintes não sofram escape duplo
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, '''); // forma numérica — segura em HTML4, HTML5 e XML
}
const userInput = `<a href="x">Tom & Jerry's</a>`;
const safe = escapeHtml(userInput);
// → <a href="x">Tom & Jerry's</a>
// Melhor em código de aplicação: deixe a plataforma escapar por você.
// el.textContent = userInput; // o navegador escapa; sem replace manual
// React / Vue / Angular escapam texto interpolado por padrão
// Templates de servidor (Jinja, ERB, Blade) auto-escapam, a menos que você opte por não
A função feita à mão é útil para entender o que acontece e para conversões pontuais, mas em produção prefira o caminho embutido. Definir element.textContent deixa o navegador escapar por você, e os frameworks modernos escapam valores interpolados automaticamente. Reserve o escape manual para os casos que a plataforma não cobre.
Para trabalho avulso, o Codificador de Entidades HTML escapa o conjunto reservado (nomeado, decimal ou hex), e o Decodificador de Entidades HTML reverte. Os dois são inversos exatos para os caracteres reservados, então você pode levar o texto de ida e volta pelos dois sem perda.
Perguntas frequentes
O que é uma entidade HTML?
Uma entidade HTML é um código curto, que começa com & e termina com ;, que representa um único caractere. O navegador renderiza o caractere para o qual a entidade aponta em vez de tratá-lo como marcação. Por exemplo, < exibe um < literal, e & exibe um & literal.
Quais caracteres preciso escapar em HTML?
Os cinco caracteres especiais reservados do HTML: <, >, &, " e '. No conteúdo de elemento você precisa principalmente de <, > e &; nos valores de atributos as aspas " e ' também se tornam críticas. Escape o e-comercial & primeiro para que as outras entidades não sofram escape duplo.
Devo usar entidades nomeadas ou numéricas (decimais/hex)?
Use entidades nomeadas (<, ©) por legibilidade com os caracteres comuns, já que são fáceis de reconhecer. Use entidades numéricas (decimal < ou hex <) quando precisar codificar um caractere sem nome definido, ou quando não puder garantir que o consumidor suporta uma dada entidade nomeada. As duas formas referenciam o mesmo ponto de código.
As entidades HTML protegem contra XSS?
Elas são a fundação, quando aplicadas corretamente. Escapar os cinco caracteres reservados antes de colocar entrada não confiável em conteúdo de elemento ou de atributo HTML barra a injeção de tags e de scripts. Mas o escape depende do contexto: blocos de script precisam de escape JavaScript e URLs precisam de codificação por porcentagem. Combine o escape correto e sensível ao contexto com CSP e o auto-escape do framework.
Por que minha página mostra &lt; em vez de <?
Isso é escape duplo. O texto foi codificado duas vezes, ou o & foi escapado depois dos sinais de menor/maior, então o & em < virou &. O visitante então vê < como texto literal. Escape exatamente uma vez e sempre escape o & primeiro. A ferramenta decodificadora consegue confirmar para que as entidades resolvem.
Preciso escapar caracteres como é, — ou emoji?
Em geral, não. Numa página que declara <meta charset="utf-8">, letras acentuadas, traços e emoji são caracteres crus válidos e não precisam de codificação — deixe-os como estão. Só codifique não-ASCII quando o texto tiver de passar por um charset legado de byte único ou por um sistema que corrompe UTF-8 cru.