FlawOpen

flawopen.com/XSS in JavaScript/DOMPurify and innerHTML

DOMPurify basta para tornar innerHTML seguro?

Guia de referência
Resposta curta

DOMPurify é um sanitizador forte baseado em lista de permissões para HTML rico quando sua saída vai diretamente a um ponto de inserção HTML, sem alterações posteriores. Pense numa encomenda inspecionada na doca: se outro processo a reembalar ou usar outra entrada, a inspeção inicial já não cobre o que chega. Para texto simples, use textContent e evite interpretar HTML.

AINDA ARRISCADO — dados sanitizados antigos chegam ao destino
// Sanitizado ao salvar com uma versão/política antiga.
saveToDb(DOMPurify.sanitize(input));

// O código posterior confia na string salva sem verificar.
el.innerHTML = fetchedFromDb;
MAIS SEGURO — sanitize para este destino HTML
// Para HTML rico, sanitize com a biblioteca atual
// imediatamente antes de inserir no contexto HTML.
el.innerHTML = DOMPurify.sanitize(untrustedHtml, {
  USE_PROFILES: { html: true },
});

// Se for texto simples, não o interprete como HTML.
textNode.textContent = untrustedText;

Por que sanitizar uma vez na entrada é um padrão mais fraco

Sanitizar ao salvar não é automaticamente inseguro, mas cria uma fronteira com dados antigos: um renderizador pode confiar em saída antiga após uma correção do sanitizador, mudança de política ou caminho que pulou a sanitização. Sanitize novamente no momento da renderização com a versão atual e a política do destino exato. Não modifique nem passe a marcação limpa por outra biblioteca antes de inseri-la; o pós-processamento pode invalidar a sanitização.

A configuração e o contexto de saída importam

A configuração padrão do DOMPurify permite HTML, SVG e MathML. Se o recurso só precisa de HTML, restrinja o perfil com USE_PROFILES: { html: true }. Não amplie tags ou atributos sem revisão. DOMPurify não sanitiza CSS nem impede toda requisição externa; use a saída apenas em HTML, nunca em JavaScript, atributo, XML, SVG ou CSS.

Trusted Types e renderização no servidor

Quando houver suporte, imponha Trusted Types com Content Security Policy para rejeitar strings em pontos de inserção HTML sem uma política aprovada. DOMPurify pode produzir TrustedHTML; isso reduz usos acidentais do destino, mas não corrige configuração insegura nem pós-processamento. No servidor, DOMPurify depende de uma implementação DOM: mantenha jsdom atualizado e não o combine com happy-dom para sanitização sensível à segurança.

Checklist de produção

Busque pontos de inserção HTML

rg -n -g '*.{js,ts,jsx,tsx}' '(innerHTML|outerHTML|insertAdjacentHTML|document\.write|dangerouslySetInnerHTML)' .
Para cada ocorrência, rastreie dados não confiáveis até o destino, confirme que a sanitização ocorre imediatamente antes da inserção e verifique se código posterior não altera a marcação.

Fontes e referências

Veja também Cross-Site Scripting (XSS, CWE-79): como funciona e como evitar em todas as linguagens — flawopen.com Markdown é seguro contra XSS? Svelte é seguro contra XSS por padrão? Upload de SVG pode causar XSS? Risco de XSS no Vue v-html WKWebView: HTML não confiável é seguro? XSS refletido, armazenado e baseado em DOM: quais são as diferenças?