Codificador / Decodificador de entidades HTML
Converta caracteres especiais em entidades HTML e vice-versa.
Entidades HTML comuns
| Caractere | Entidade | Numérica | Descrição |
|---|---|---|---|
| & | & | & | E comercial |
| < | < | < | Menor que |
| > | > | > | Maior que |
| " | " | " | Aspas duplas |
| ' | ' | ' | Apóstrofo |
| |   | Espaço inquebrável | |
| © | © | © | Copyright |
| ® | ® | ® | Marca registrada |
| ™ | ™ | ™ | Marca comercial |
| € | € | € | Símbolo do euro |
Por que usar entidades HTML ?
Caracteres como <, > e & têm significado especial em HTML. Se você incluí-los literalmente no seu HTML, o navegador os interpreta como código, não como conteúdo. Codificar esses caracteres em entidades evita problemas de renderização e vulnerabilidades de script cross-site (XSS).
Perguntas frequentes
Qual a diferença entre entidades nomeadas e numéricas ?
As entidades nomeadas usam nomes descritivos (&, ©) enquanto as entidades numéricas usam pontos de código Unicode (&, ©). As duas são exibidas de forma idêntica. As entidades nomeadas são mais legíveis ; as entidades numéricas funcionam para qualquer caractere Unicode.
Devo codificar todos os caracteres especiais ?
No mínimo, você deve codificar &, <, > e " no conteúdo HTML e nos valores de atributos. Os navegadores modernos lidam com a maioria dos outros caracteres nativamente se o seu documento usar a codificação UTF-8.
Três formas, um caractere
Uma «entidade» HTML, formalmente uma referência de caractere: é uma sequência de escape que representa um caractere usando uma sequência de caracteres ASCII comuns. O HTML Living Standard define três formas sintáticas concretas:
- Nomeada:
&seguido de um nome da tabela de referências de caractere nomeadas da WHATWG, terminado por um ponto e vírgula. Exemplo:©para ©. - Numérica decimal:
&#seguido do ponto de código Unicode em base 10, terminado por um ponto e vírgula. Exemplo:©. - Numérica hexadecimal:
&#xseguido do ponto de código em base 16, terminado por um ponto e vírgula. Exemplo:©.
As três formas são intercambiáveis quando renderizadas: ©, © e © produzem todas o caractere visível © porque todas resolvem para o ponto de código Unicode U+00A9. A escolha entre elas é uma questão de legibilidade do código-fonte, não de comportamento do navegador. O hex tende a corresponder aos gráficos Unicode publicados (que usam a notação U+XXXX), então ♥ está mais perto da notação oficial U+2665 do que ♥. As referências numéricas funcionam para qualquer caractere Unicode, incluindo emoji do plano astral, 😀 é renderizado como 😀 (U+1F600 GRINNING FACE).
Por que as entidades existem
Três razões distintas, históricas e práticas:
- Para escapar caracteres que têm significado sintático no HTML. O parser usa certos caracteres ASCII como símbolos de controle. O
<abre uma tag, o>fecha uma, o&introduz uma referência, e os caracteres de aspas delimitam os valores de atributo. Se você quiser que qualquer um deles apareça como texto literal, você precisa escapá-lo. - Para representar caracteres não disponíveis na codificação do documento. Antes de o UTF-8 se tornar universal na web (só passou da marca de 50% por volta de 2010), a maioria do HTML era servida como US-ASCII, ISO-8859-1 ou Windows-1252. Nessas codificações de byte único, caracteres como ©, €, ≈ ou α simplesmente não podiam ser expressos por um byte literal. Escrever
©,€ou≈era a única forma de alcançar esses pontos de código. - Para sinalizar a intenção do autor para caracteres invisíveis ou ambíguos. Mesmo em uma página UTF-8, um espaço sem quebra literal (U+00A0) é visualmente idêntico a um espaço normal, escrever
torna a intenção óbvia para qualquer um que leia o código-fonte.
O W3C agora recomenda usar caracteres Unicode literais sempre que possível, em vez de entidades, «por acessibilidade e legibilidade». As entidades continuam úteis para os cinco escapes obrigatórios, além de caracteres genuinamente invisíveis ou ambíguos.
Os Cinco Grandes
Os cinco caracteres que você absolutamente precisa escapar ao inserir conteúdo não confiável no HTML são <, >, &, " e '. A Cross-Site Scripting Prevention Cheat Sheet da OWASP os enumera como o conjunto mínimo de escapes obrigatório:
| Caractere | Nomeada | Decimal | Hex |
|---|---|---|---|
| < | < | < | < |
| > | > | > | > |
| & | & | & | & |
| " | " | " | " |
| ' | ' / ' | ' | ' |
A regra prática: sempre que você colocar texto não confiável em uma saída HTML, escape esses cinco caracteres primeiro. Não fazer isso é a causa raiz da esmagadora maioria das vulnerabilidades de XSS armazenado e refletido.
A armadilha do apóstrofo
O ' não faz parte do HTML 4, ele foi originalmente definido apenas pelo XML 1.0 e herdado pelo XHTML 1.0. O Internet Explorer anterior à versão 9 (lançada em 2011) se recusava a renderizá-lo como ' e exibia o texto literal '. A entidade foi adicionada especificamente ao HTML5 e agora é segura em todo navegador moderno, mas, para a máxima compatibilidade entre navegadores e specs, a OWASP e a maioria das bibliotecas corporativas de sanitização ainda recomendam emitir ' em vez de ' ao escapar aspas simples, particularmente em código crítico de segurança.
Quando codificar e quando não
A decisão de codificação depende de onde o texto vai parar na saída, não do que ele contém. Este é o ponto mais mal compreendido na segurança de HTML. A orientação da OWASP distingue os contextos:
- Conteúdo de elemento HTML: escape
< > & "(e'por paranoia). - Valores de atributo HTML: escape os mesmos mais o caractere de aspas; sempre use atributos entre aspas.
- Contexto JavaScript: use o escape de JavaScript, não o escape de HTML:
\xHHou\uHHHH. - Contexto CSS: use o escape de CSS:
\HHseguido de um espaço. - Contexto de parâmetro de URL / URI: use a codificação percentual (
%HH), não a codificação HTML.
Cada contexto tem as suas próprias regras de escape. Misturá-las é por si só uma vulnerabilidade, por exemplo, codificar em percentual um < para %3C não protege contra XSS no contexto de conteúdo de elemento HTML, onde %3C é apenas o texto literal %3C.
Evite a codificação dupla. Um bug comum é escapar os dados quando são lidos para dentro do sistema, de novo quando são armazenados, de novo quando são lidos de volta, e de novo quando são renderizados. O resultado: o usuário digitou 5 < 10, o banco de dados armazena 5 &lt; 10, a página renderiza 5 < 10 em vez do original. A disciplina é: armazene Unicode bruto, codifique uma vez, no momento da saída, para o contexto específico.
Codificação HTML vs. codificação URL
Dois sistemas de escape diferentes para dois contextos diferentes, confundidos o tempo todo:
| Entidade HTML | URL / percentual | |
|---|---|---|
| Padrão | HTML Living Standard | RFC 3986 |
| Formato | &name; ou &#NN; | %HH (byte hex) |
| Contexto | Marcação HTML, corpos de elemento e atributos | URLs, query strings, corpos de requisição com codificação de formulário |
| Espaço | (sem quebra), nunca um espaço comum | %20 ou + |
| Função JS | - (o parser cuida) | encodeURIComponent() / encodeURI() |
Uma URL dentro de um valor de atributo HTML recebe os dois escapes em camadas: primeiro a codificação percentual para os caracteres ilegais em URL, depois a codificação HTML para qualquer & < > " na URL resultante. É por isso que os e-comerciais de query string dentro de um atributo href viram & na serialização HTML.
Uma breve história
O HTML 2.0 (RFC 1866, 1995) herdou o mecanismo de entidades do SGML, com cerca de 50 entidades nomeadas para o ISO Latin 1. O HTML 3.2 (W3C, janeiro de 1997) acrescentou as entidades matemáticas e de símbolos. O HTML 4.01 (W3C, dezembro de 1999) finalizou três conjuntos de entidades (Latin-1, Special e Symbol), totalizando 252 entidades nomeadas, que é a origem do número «252» ainda visto em tutoriais mais antigos. O HTML5 / WHATWG (Living Standard, em andamento) absorveu e expandiu drasticamente a tabela para mais de 2.000 entradas, principalmente para cobrir o MathML e um conjunto Unicode mais amplo. O XML 1.0 (1998) define o seu próprio conjunto mínimo só dos Cinco Grandes (< > & " '), e esse conjunto mínimo é a origem do '.
Mais perguntas
No código moderno, o que eu deveria realmente usar?
O código de produção geralmente não escreve à mão a codificação de entidades, ele chama uma biblioteca. DOMPurify para a sanitização de HTML no lado do cliente. html.escape() na biblioteca padrão do Python. htmlspecialchars() no PHP. html/template no Go (autoescape ligado por padrão). OWASP Java Encoder para o Java. No React, escrever <div>{userInput}</div> escapa automaticamente; a válvula de escape dangerouslySetInnerHTML tem esse nome para desencorajar o uso casual. Um codificador independente como este é útil como ferramenta de verificação / depuração, não um substituto para essas bibliotecas.
E quanto a tags dentro de templates de e-mail?
Os clientes de e-mail mais antigos (o Outlook em particular) interpretam um & não codificado como um atributo malformado e podem remover a marcação ao redor. Os desenvolvedores de e-mail em HTML aprendem a codificar em entidade todo caractere especial de forma defensiva. O mesmo se aplica aos sistemas de fórum no estilo BBCode que reescrevem o conteúdo antes de armazená-lo; as idas e voltas podem introduzir entidades literais inesperadas.
O que é textContent vs. innerHTML no JavaScript?
A regra de prevenção de XSS mais importante no JavaScript puro: use element.textContent = userInput em vez de element.innerHTML = userInput. Definir textContent escreve a string como texto literal, o navegador cuida de todo o escape internamente. Definir innerHTML analisa a string como HTML, executando quaisquer tags <script> ou atributos de manipulador de evento que ela contenha. Se a marcação for genuinamente necessária, use uma biblioteca como o DOMPurify para sanitizar primeiro.
O codificador lida com emoji?
Sim, via referências numéricas. Não há entidades nomeadas para emoji, todos usam a forma numérica. 😀 é renderizado como 😀, ❤️ como o coração vermelho ❤️ (ponto de código do coração mais o seletor de apresentação de emoji). O navegador cuida da conversão implícita de par substituto UTF-16 internamente; você não deveria escrever as metades substitutas manualmente.
Algo é enviado a um servidor?
Não. A codificação e a decodificação são transformações de string de função pura rodando inteiramente no seu navegador via JavaScript. Nada sobre a sua entrada é enviado; a página funciona offline depois de carregada. Isso importa porque codificadores baseados em nuvem que fazem a ida e volta da sua carga de teste podem eles mesmos se tornar um vetor de XSS se o site de teste for comprometido.