O Que São Entidades HTML?
Entidades HTML são sequências de texto especiais usadas para representar caracteres que possuem um significado reservado no HTML ou que não podem ser facilmente digitados ou transmitidos. Uma entidade começa com um e comercial (&) e termina com um ponto e vírgula (;). Entre esses delimitadores, encontra-se um nome descritivo (uma entidade nomeada como &) ou um ponto de código numérico (uma entidade numérica como & ou &).
À primeira vista, as entidades parecem um detalhe tipográfico menor. Na realidade, elas são um pilar da segurança web, da internacionalização e da renderização confiável nos navegadores. Todo desenvolvedor web que trabalha com conteúdo dinâmico — entradas de usuário, dados de CMS, modelos de e-mail ou mecanismos de templates — deve entender como e quando codificar entidades HTML.
Uma Breve História das Entidades HTML e da Codificação de Caracteres
A Era ASCII (anos 1960–1980)
O American Standard Code for Information Interchange (ASCII) definia 128 caracteres: as 26 letras inglesas (maiúsculas e minúsculas), dígitos, pontuação e códigos de controle. Isso era suficiente para o inglês americano, mas completamente inadequado para o resto dos idiomas do mundo.
Latin-1 / ISO-8859-1 (anos 1980–1990)
O ISO-8859-1 (também chamado de Latin-1) estendeu o ASCII para 256 caracteres usando o 8º bit, adicionando caracteres acentuados usados nos idiomas da Europa Ocidental (é, ü, ñ, etc.). O HTML 2.0 e o HTML 3.2 adotaram formalmente o Latin-1 como seu conjunto de caracteres de referência, e as entidades nomeadas do HTML para muitos desses caracteres foram definidas nessa época — entidades como é (é), ü (ü) e ñ (ñ).
O problema: 256 caracteres ainda não conseguiam cobrir o japonês, árabe, chinês, coreano ou centenas de outras escritas. Diferentes regiões inventaram codificações incompatíveis (Shift-JIS, Big5, KOI8-R…), criando o problema "Mojibake" — texto ilegível quando as codificações eram misturadas.
Unicode e UTF-8 (1991–Presente)
O Consórcio Unicode publicou seu primeiro padrão em 1991 com o objetivo de atribuir um ponto de código único a cada caractere em cada sistema de escrita. Hoje, o Unicode cobre mais de 140.000 caracteres em mais de 150 escritas.
O UTF-8, introduzido em 1992 por Ken Thompson e Rob Pike, codifica os pontos de código Unicode como 1–4 bytes e é retrocompatível com o ASCII. Ele se tornou a codificação dominante para a web nos anos 2000. Em 2024, mais de 98% das páginas web usam UTF-8.
Por que as Entidades ainda Importam em um Mundo UTF-8?
Se podemos codificar qualquer caractere com UTF-8, por que as entidades ainda existem? Três razões:
- Caracteres reservados:
<,>, e&possuem significado especial na marcação HTML. Mesmo em documentos UTF-8, você deve escapá-los para exibi-los literalmente. - Delimitadores de atributos:
"e'delimitam valores de atributos e devem ser escapados dentro desses valores. - Controle de espaços em branco:
(espaço não separável) controla o layout de formas que espaços regulares não conseguem.
Conceitos Básicos: Como as Entidades HTML Funcionam
Entidades Nomeadas
Entidades nomeadas são a forma mais legível para humanos, usando um nome mnemônico derivado da descrição do caractere. O HTML5 define mais de 2.000 entidades nomeadas.
<!-- Usando entidades nomeadas -->
<p>Pão & Manteiga</p> <!-- exibe: Pão & Manteiga -->
<p>3 < 5 e 10 > 7</p> <!-- exibe: 3 < 5 e 10 > 7 -->
<p>Copyright © 2026</p> <!-- exibe: Copyright © 2026 -->
<p>Preço: 49€</p> <!-- exibe: Preço: 49€ -->
Entidades Numéricas: Decimal e Hexadecimal
Qualquer caractere Unicode pode ser referenciado pelo seu ponto de código em forma decimal ou hexadecimal:
- Decimal:
&#seguido pelo ponto de código decimal — ex:<para<(U+003C) - Hexadecimal:
&#xseguido pelo ponto de código hex — ex:<para<
Ambas as formas são equivalentes. O hexadecimal é comum em documentação técnica porque os pontos de código Unicode são normalmente expressos em hex (U+003C).
<!-- As três são formas equivalentes de exibir < -->
<
<
<
As 5 Entidades de Segurança Críticas
Estes cinco caracteres formam a base da defesa contra injeção de HTML:
| Caractere | Entidade Nomeada | Decimal | Hex | Contexto |
|---|---|---|---|---|
< |
< |
< |
< |
Abre tags HTML |
> |
> |
> |
> |
Fecha tags HTML |
& |
& |
& |
& |
Inicia entidades |
" |
" |
" |
" |
Atributos com aspas duplas |
' |
' |
' |
' |
Atributos com aspas simples |
Sempre codifique os cinco ao refletir a entrada do usuário no HTML.
Tabela de Referência de Entidades HTML
| Caractere | Entidade Nomeada | Decimal | Hex | Uso |
|---|---|---|---|---|
< |
< |
< |
< |
Delimitadores de tag |
> |
> |
> |
> |
Delimitadores de tag |
& |
& |
& |
& |
Prefixo de entidade |
" |
" |
" |
" |
Valores de atributos |
' |
' |
' |
' |
Valores de atributos |
|
|
  |
  |
Espço não separável |
© |
© |
© |
© |
Copyright |
® |
® |
® |
® |
Marca registrada |
™ |
™ |
™ |
™ |
Marca comercial |
€ |
€ |
€ |
€ |
Sinal do Euro |
— |
— |
— |
— |
Travessão (em dash) |
– |
– |
– |
– |
Meio-travessão (en dash) |
Prevenção de XSS: Por Que a Codificação Salva Seu Site
O Cross-Site Scripting (XSS) é uma das vulnerabilidades de segurança web mais prevalentes. Ocorre quando um invasor injeta scripts maliciosos em conteúdo que é servido a outros usuários. A codificação de entidades HTML é a defesa primária.
O Ataque XSS Clássico
Considere um recurso de busca que exibe de volta a consulta do usuário:
<!-- VULNERÁVEL: inserindo diretamente a entrada do usuário -->
<p>Você buscou por: <?php echo $_GET['q']; ?></p>
Um invasor cria uma URL como:
https://exemplo.com/search?q=<script>document.cookie</script>
O navegador renderiza a tag <script> e executa o código do invasor. Com document.cookie, eles roubam tokens de sessão. Com fetch(), eles exfiltram dados para um servidor controlado pelo invasor.
A Solução: Codificar na Saída
<!-- SEGURO: codificar toda a saída -->
<p>Você buscou por: <?php echo htmlspecialchars($_GET['q'], ENT_QUOTES, 'UTF-8'); ?></p>
Agora o navegador vê:
<p>Você buscou por: <script>document.cookie</script></p>
O script é exibido como texto inofensivo — nenhuma execução ocorre.
Exemplos Práticos de Código
JavaScript: Manipulação Segura do DOM
A maneira mais segura de inserir conteúdo gerado pelo usuário no JavaScript é via textContent, que nunca interpreta HTML:
// SEGURO: textContent nunca analisa HTML
const el = document.getElementById('output');
el.textContent = userInput; // escapa automaticamente tudo
// PERIGOSO: innerHTML analisa e executa HTML
el.innerHTML = userInput; // NUNCA faça isso com entrada não confiável
Se você precisar construir strings HTML no JavaScript, sempre escape primeiro:
function escapeHtml(str) {
return str
.replace(/&/g, '&') // deve vir primeiro
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''');
}
const safe = `<p>Você buscou por: ${escapeHtml(userInput)}</p>`;
Nota: sempre escape & primeiro — se você escapar < primeiro, o & em < seria ele mesmo escapado para &lt;, causando codificação dupla.
PHP: htmlspecialchars() e htmlentities()
O PHP fornece duas funções principais para codificação HTML:
// htmlspecialchars: codifica apenas os 5 caracteres críticos
$safe = htmlspecialchars($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
// htmlentities: codifica TODOS os caracteres com equivalentes em entidades nomeadas
$safe = htmlentities($input, ENT_QUOTES | ENT_HTML5, 'UTF-8');
Diferença chave: htmlspecialchars() codifica apenas <, >, &, " e '. htmlentities() também codifica letras acentuadas e símbolos como é → é. Para documentos UTF-8, htmlspecialchars() é geralmente preferido — o UTF-8 pode representar todos os caracteres diretamente; apenas os cinco perigosos precisam de escape.
Sempre passe ENT_QUOTES para codificar ambos os tipos de aspas, e sempre especifique 'UTF-8' como o charset.
Python: html.escape()
import html
# Escape básico
safe = html.escape(user_input)
# Escape aspas simples também (quote=True é o padrão desde Python 3.2)
safe = html.escape(user_input, quote=True)
# Exemplo
user_input = '<script>alert("XSS")</script>'
print(html.escape(user_input))
# Saída: <script>alert("XSS")</script>
Templates HTML (Jinja2, Django, Handlebars)
A maioria dos sistemas de templates modernos faz o auto-escape por padrão:
<!-- Jinja2 / Django: auto-escape por padrão -->
<p>{{ user_comment }}</p>
<!-- Renderizar HTML bruto deliberadamente (PERIGOSO se controlado pelo usuário): -->
<p>{{ user_comment | safe }}</p>
<!-- Handlebars: chaves duplas escapam, chaves triplas não -->
<p>{{userComment}}</p> <!-- escapado — seguro -->
<p>{{{userComment}}}</p> <!-- HTML bruto — perigoso! -->
Casos de Uso no Mundo Real
1. Documentação Técnica e Blogs de Código
Ao escrever sobre HTML, você frequentemente precisa mostrar exemplos de código contendo <, >, e &. Entidades permitem exibir esses caracteres como literais sem quebrar a estrutura da página:
<pre><code>
Use <div> e </div> para envolver seções.
O caractere & inicia uma entidade HTML.
</code></pre>
2. CMS e Conteúdo Gerado pelo Usuário
Qualquer CMS que armazena e exibe texto gerado pelo usuário deve codificar entidades HTML antes de enviá-lo para a página. Isso inclui comentários de blog, postagens em fóruns, avaliações de produtos e postagens em redes sociais. A falha em fazer isso é responsável por uma enorme proporção de incidentes reais de XSS.
3. Templates de E-mail HTML
Clientes de e-mail são notoriamente inconsistentes. Usar entidades nomeadas para caracteres tipográficos (—, ‘, ’, …) ajuda a garantir a renderização correta no Gmail, Outlook, Apple Mail e clientes antigos como Outlook 2007 (que usa o mecanismo de renderização do Word).
4. Tipografia e Símbolos Especiais
Entidades fornecem acesso confiável a caracteres tipográficos que são difíceis de digitar ou que podem não sobreviver ao copiar e colar entre sistemas:
<p>O travessão—usado para incisos—é mais expressivo que um hífen.</p>
<p>Ela disse “olá” e sorriu.</p>
<p>Preço: 29 €</p>
<!-- evita que "29" e "€" quebrem para linhas separadas -->
5. Internacionalização em Sistemas Legados
Em sistemas legados que não conseguem lidar de forma confiável com UTF-8, entidades numéricas permitem a codificação de qualquer caractere Unicode:
<!-- Caractere chinês para "dragão" (U+9F99) como entidade decimal -->
龙
<!-- Hiragana japonês あ (U+3042) -->
あ
Entidades Nomeadas vs. Numéricas: Comparação
| Aspecto | Nomeada (<) |
Decimal (<) |
Hexadecimal (<) |
|---|---|---|---|
| Legibilidade | Alta | Média | Baixa |
| Abrangência | ~2.000 chars | Todo o Unicode | Todo o Unicode |
| Suporte HTML5 | Total | Total | Total |
| Suporte XML | Apenas as 5 predefinidas | Total | Total |
| Melhor para | Caracteres comuns | Qualquer Unicode | Refs técnicas/Unicode |
HTML vs. XML: Uma Diferença Crítica
O XML predefine apenas 5 entidades (<, >, &, ", '). Todas as outras entidades nomeadas como © ou são não definidas no XML, a menos que declaradas em um DTD.
<!-- INVÁLIDO no XML (entidade não definida): -->
<p>Copyright © 2026</p>
<!-- VÁLIDO no XML (entidade numérica funciona em qualquer lugar): -->
<p>Copyright © 2026</p>
<!-- VÁLIDO no HTML5 (ambas funcionam): -->
<p>Copyright © 2026</p>
Se você estiver escrevendo XHTML ou SVG, use entidades numéricas para qualquer coisa além das 5 básicas, ou use o caractere UTF-8 literal diretamente.
Melhores Práticas
1. Use UTF-8 em Todo o Seu Stack
Declare UTF-8 em todos os lugares — na intercalação do banco de dados, no cabeçalho HTTP Content-Type e na tag HTML <meta charset>. Isso elimina a necessidade de codificar caracteres não ASCII com entidades.
<meta charset="UTF-8">
header('Content-Type: text/html; charset=UTF-8');
2. Codifique de Acordo com o Contexto
Diferentes contextos de injeção exigem diferentes estratégias de escape:
- Corpo HTML: codifique
<,>,& - Atributos HTML: codifique
<,>,&,",' - Strings JavaScript: use escape
\uXXXXou codificação JSON - Valores CSS: regras de escape diferentes se aplicam
- URLs: use codificação percentual (
%3Cem vez de<)
Um caractere codificado para um contexto não é necessariamente seguro em outro.
3. Codifique na Saída, Não na Entrada
Armazene dados brutos no seu banco de dados. Codifique ao enviar para o HTML. Se você codificar na entrada, corre o risco de codificação dupla na saída, e os dados tornam-se corrompidos em contextos não HTML (APIs JSON, e-mails em texto simples, etc.).
4. Nunca Decodifique Entrada Não Confiável Antes do Processamento
Decodificar entidades fornecidas pelo usuário antes de aplicar filtros de segurança derrota o propósito. <script> decodificado torna-se <script> — um bypass clássico de filtros ingênuos que apenas bloqueiam sinais de menor e maior.
5. Evite Codificação Dupla
Codificação dupla (&lt; que renderiza como <, não <) é um erro comum quando múltiplas camadas da aplicação codificam de forma independente. Centralize sua codificação em uma única camada de apresentação.
6. Lembre-se que ' Não Estava no HTML4
A entidade ' é definida no XML e XHTML, mas não estava definida no HTML4. Em ambientes HTML4, use ' em vez disso. O HTML5 adicionou oficialmente ' à lista de entidades nomeadas.
Perguntas Frequentes
P: Preciso codificar todos os caracteres especiais ou apenas os perigosos?
Para segurança, você deve codificar pelo menos os 5 caracteres críticos (< > & " '). Para tipografia (símbolos de copyright, travessões, símbolos de moeda), usar o caractere UTF-8 literal em um documento UTF-8 é perfeitamente aceitável. Entidades são mais críticas em sistemas legados ou quando a codificação de caracteres não pode ser garantida.
P: Qual é a diferença entre & e &?
& é o caractere de e comercial literal. & é sua representação em entidade HTML. No código-fonte HTML, sempre que você quiser exibir um & literal, deve escrever &. Se você escrever o & isolado antes de uma palavra, os navegadores podem tentar interpretá-lo como o início de uma entidade e renderizar incorretamente.
P: Por que se comporta de forma diferente de um espaço regular?
Um espaço regular (U+0020) é um espaço que permite quebra — navegadores podem quebrar linhas nele, e múltiplos espaços consecutivos colapsam em um. (espaço não separável, U+00A0) evita quebras de linha entre os caracteres adjacentes e não colapsa. Útil para manter valores como "100 km" ou "Dr. Silva" em uma única linha.
P: Posso usar entidades numéricas para emojis?
Sim. Emojis têm pontos de código Unicode e podem ser representados como entidades numéricas. O emoji 😀 (U+1F600) é 😀 em hex ou 😀 em decimal. Em documentos UTF-8, você pode colar o emoji diretamente, mas entidades numéricas funcionam como um fallback confiável.
P: Qual é o risco de XSS específico para atributos href?
O atributo href possui um perigo único: URLs podem usar o protocolo javascript:. A codificação HTML sozinha não é suficiente:
<!-- PERIGOSO mesmo que < e > estejam codificados: -->
<a href="javascript:alert(1)">Clique aqui</a>
<!-- Seguro: valide se o href começa com http:// ou https:// -->
<?php
$url = $_GET['url'];
if (!preg_match('/^https?:\/\//i', $url)) {
$url = '#'; // rejeita protocolos perigosos
}
echo '<a href="' . htmlspecialchars($url) . '">Link</a>';
?>
P: É seguro usar innerHTML se eu codificar o conteúdo primeiro?
Se você codificar corretamente todos os 5 caracteres críticos antes de atribuir ao innerHTML, geralmente é seguro para injetar texto simples. No entanto, textContent é mais simples e seguro. Reserve o innerHTML para casos onde você intencionalmente deseja inserir uma estrutura HTML controlada.
P: Os frameworks JavaScript modernos lidam com codificação HTML automaticamente?
Sim — React, Vue, Angular e Svelte escapam a saída por padrão. O JSX do React escapa automaticamente valores interpolados com {}. No entanto, cada um fornece um bypass explícito (o dangerouslySetInnerHTML do React, o v-html do Vue) que deve ser usado com extremo cuidado e apenas com conteúdo confiável.
Resumo
Entidades HTML são um mecanismo essencial para:
- Segurança — neutralizar
<,>,&,", e'para prevenir injeção de XSS - Correção — garantir que caracteres com significado reservado no HTML sejam exibidos literalmente
- Compatibilidade — representar qualquer caractere Unicode em ambientes legados ou restritos
- Tipografia — inserir travessões, espaços não separáveis, símbolos de moeda e outros caracteres especiais de forma confiável
Em um stack UTF-8 moderno, você precisa codificar principalmente os 5 caracteres críticos de segurança ao enviar conteúdo dinâmico para o HTML. Entidades nomeadas como e — continuam sendo úteis para a tipografia. Entender a diferença entre entidades nomeadas e numéricas, e a divergência entre as regras de HTML e XML, tornará você um desenvolvedor web mais eficaz e consciente da segurança.