HTML usa os mesmos caracteres para conteúdo visível e estrutura. O sinal de menor pode aparecer em uma fórmula, mas também inicia uma tag. O ampersand pode fazer parte de um nome, mas inicia uma character reference. Entidades HTML oferecem uma forma de representar o caractere literal sem deixar o parser interpretá-lo como markup.
Texto e markup compartilham o canal
No conteúdo textual, < produz um sinal de menor e & produz ampersand. Referências nomeadas como © são legíveis; referências numéricas apontam para code points Unicode.
UTF-8 permite escrever a maioria dos caracteres diretamente. Entidades continuam úteis quando o caractere possui significado sintático ou quando a forma ASCII comunica intenção.
Escaping depende do destino
Texto entre tags, atributo, URL, CSS e JavaScript possuem gramáticas diferentes. Escapar aspas para um atributo não protege uma string dentro de script.
Template engines devem escolher encoder pelo contexto. Concatenar markup manualmente ou mover valor já escaped entre contextos cria falhas.
Encoding não é sanitization
Encoding mostra <strong> como texto. Sanitization permite um subconjunto de HTML, parseando e removendo elementos, atributos e URLs perigosas.
Se rich text não é necessário, escape tudo. Decodificar antes de raw rendering pode reintroduzir markup malicioso.
Double encoding revela ownership duplicado
Quando backend e template escapam, o usuário vê &lt;. O problema não se resolve com decode no browser, mas definindo qual camada possui a saída.
Armazene texto sem apresentação e escape no boundary final. HTML sanitizado deve ser um tipo ou campo separado.
Entidades não mudam o valor Unicode
Caractere direto, referência decimal, hexadecimal e nomeada podem produzir o mesmo DOM. A forma do source muda, o caractere final não.
Unicode normalization é outro problema. Entidades não tornam strings visualmente iguais byte a byte.
Browsers recuperam HTML malformado
O parser possui regras complexas de error recovery. Filtros de string podem interpretar diferente do navegador. Atacantes exploram essa divergência.
Use encoders e sanitizers maduros. Regex e replacements não modelam toda a gramática.
Source e DOM mostram etapas diferentes
View source revela o que o servidor enviou. DevTools mostra o DOM após parsing e scripts. Comparar ambos localiza se o problema está em storage, template ou código cliente.
Validators ajudam com source; browser tests confirmam comportamento.
Editores podem alterar representação
WYSIWYG pode converter caracteres, normalizar tags e reordenar atributos. Se abrir e salvar produz diff enorme, auditoria perde clareza.
Texto simples deve permanecer sem markup. HTML rico precisa de policy de normalização e preview sanitizado.
Nem todo caractere precisa virar entidade
Converter todo Unicode torna o source longo. UTF-8 direto é mais legível para texto comum. Use entities para sintaxe e símbolos onde a intenção melhora.
O objetivo é documento seguro e legível, não quantidade máxima de escapes.
Ownership precisa aparecer nos tipos
Plain text, sanitized HTML e URL não deveriam circular como strings indistinguíveis. Nomes de campos e helpers ajudam reviewers a saber qual operação é permitida.
APIs também devem declarar o tipo. Clientes não deveriam adivinhar procurando tags.
Portabilidade do source precisa de uma convenção
Times podem escolher UTF-8 direto para letras e entidades para caracteres sintáticos. O importante é consistência. Converter automaticamente todos os caracteres não ASCII dificulta revisão e aumenta diffs sem melhorar segurança.
Formatters, CMS e importadores precisam seguir a mesma convenção para que o conteúdo não mude de representação a cada round trip.
Validation não substitui browser testing
Um validator encontra markup inválido, mas browsers aplicam error recovery. Componentes com conteúdo legado ou de terceiros devem ser testados em rendering real, especialmente quando existe sanitization.
O DOM final é a estrutura que scripts e usuários recebem. Ele pode diferir do source de maneira relevante.
Source, DOM e texto visível respondem perguntas diferentes
O source mostra os bytes entregues pelo servidor, enquanto o inspetor exibe o DOM depois que o parser corrigiu markup e scripts fizeram alterações. Já copiar o conteúdo revela o texto que o usuário percebe. Ao investigar uma entidade inesperada, é importante observar as três camadas em vez de concluir pelo primeiro painel aberto.
Uma sequência como & no source pode resultar em & visível, enquanto a mesma sequência inserida por textContent segue outro caminho. Testes devem afirmar o resultado apropriado para cada fronteira, não apenas procurar substrings na resposta HTTP.
A política deve pertencer à camada de saída
Um serviço que fornece plain text não deveria decidir como um template HTML o representa. Manter essa responsabilidade no renderer permite reutilizar o valor em JSON, notificações, documentos e interfaces nativas sem desfazer escapes anteriores.
Helpers tipados e auto-escaping tornam o caminho comum seguro. Quando uma aplicação realmente transporta HTML sanitizado, essa condição precisa ser explícita no schema e no código para que raw rendering não se espalhe para strings comuns.
Entidades são uma ferramenta de sintaxe
Elas não criptografam nem escondem. Mantêm a separação entre conteúdo e estrutura. A prática segura é armazenar texto sem apresentação, escapar para o contexto exato e sanitizar apenas HTML permitido.
Com essa disciplina, desaparecem tanto artefatos de double encoding quanto uma parte importante das vulnerabilidades de injeção.