Introdução ao script de Cross-Site (XSS) e defesas JavaScript

O script de Cross-site (XSS) é uma das vulnerabilidades de segurança mais prevalentes da Web, classificando- se consistentemente no Top 10 do OWASP. Um ataque XSS permite que um atacante injecte scripts maliciosos do lado do cliente em páginas web visualizadas por outros utilizadores. Estes scripts podem roubar tokens de sessão, redirecionar os utilizadores para sites de phishing, desfacelar páginas ou instalar malware. Enquanto a higienização do lado do servidor é crítica, o JavaScript desempenha um papel fundamental do lado do cliente para detectar e prevenir estes ataques. Este artigo fornece um guia abrangente e pronto para a produção para usar o JavaScript para proteger as suas aplicações do XSS.

Compreender os Três Tipos de XSS

Antes de mergulhar na prevenção, é essencial entender as três categorias primárias do XSS: armazenadas, refletidas e baseadas em DOM. Cada uma requer uma abordagem de detecção e prevenção ligeiramente diferente.

XSS Armazenado

O XSS armazenado (persistente) ocorre quando a entrada maliciosa é armazenada permanentemente no servidor (por exemplo, em um banco de dados, post no fórum ou comentário) e depois servida aos usuários sem higienização adequada. A carga útil de ataque é executada no navegador de qualquer pessoa que visualize o conteúdo armazenado.

XSS refletido

O XSS refletido acontece quando o script malicioso é refletido em um servidor web, normalmente através de um parâmetro URL ou submissão de formulário. O atacante engana uma vítima para clicar em um link criado, e o código injetado executa imediatamente. Ao contrário do XSS armazenado, a carga útil não persiste.

XSS baseado em DOM

O XSS baseado no DOM é uma vulnerabilidade puramente do lado do cliente. O carregamento de carga útil do ataque modifica o ambiente DOM no navegador da vítima. O código malicioso nunca toca no servidor; ele é originado do JavaScript do lado do cliente que lida com inseguramente a entrada do usuário (por exemplo, lendo de , , ou ).

Detecta Ataques XSS com JavaScript

A detecção é sobre a identificação de atividade suspeita antes que ocorra dano. O JavaScript pode monitorar entradas de usuário, rastrear mutações DOM e validar dados em pontos de entrada. Enquanto a detecção do lado do cliente não pode capturar todos os ataques (especialmente se o atacante faz pedidos diretamente para o servidor), ele fornece uma primeira linha valiosa de defesa.

Validação e higienização de entrada

Validar e higienizar sempre as entradas do usuário no lado do cliente antes de processar. Use em vez de para evitar a execução do script. A seguinte função retira caracteres perigosos de uma string:

function sanitizeInput(input) {
 const div = document.createElement('div');
 div.textContent = input;
 return div.innerHTML;
}

Isto funciona porque a configuração não interpreta as tags HTML; trata tudo como texto simples. O resultado contém versões escapadas de quaisquer caracteres especiais HTML (por exemplo, , , ]).

Monitorando mutações DOM para elementos suspeitos

Os atacantes frequentemente injetam tags ou manipuladores de eventos (, ) no DOM. Usando a API , você pode assistir a inserções inesperadas de elementos. Um exemplo básico:

const observer = new MutationObserver((mutations) => {
 mutations.forEach((mutation) => {
 mutation.addedNodes.forEach((node) => {
 if (node.nodeType === 1) { // element node
 if (node.tagName === 'SCRIPT') {
 console.warn('Potential XSS: a script element was injected via DOM.');
 node.remove(); // or log and analyze
 }
 // Check for dangerous attributes
 if (node.hasAttribute('onerror') || node.hasAttribute('onload')) {
 console.warn('Suspicious event handler attribute detected.');
 }
 }
 });
 });
});
observer.observe(document.body, { childList: true, subtree: true });

Cuidado: Os scripts de bloqueio via podem ser contornados por atacantes inteligentes e podem quebrar a funcionalidade legítima. Use isso como uma ferramenta de monitoramento ao invés de um mecanismo de prevenção primária.

Validando os parâmetros URL e Hash

Para o XSS baseado em DOM, leia componentes URL com segurança usando e evite inserir diretamente valores em HTML. Detecte tentativas de passar código executável:

const params = new URLSearchParams(window.location.search);
const userParam = params.get('name');
if (userParam && /[<>"'\/]/.test(userParam)) {
 console.warn('Potential XSS in parameter: ' + userParam);
 // Do not use this value in the DOM without encoding
}

Prevenção de ataques XSS com JavaScript

A prevenção requer uma abordagem multicamadas. O JavaScript sozinho não pode garantir totalmente uma aplicação, mas quando combinado com a higienização adequada da infra-estrutura e Content Security Policy (CSP), reduz drasticamente o risco.

Codificar todos os dados controlados pelo usuário antes de inserir no DOM

A regra dourada: nunca insira dados não confiáveis diretamente no DOM. Use métodos DOM seguros em vez de inerHTML.

Utilização ou

const userInput = getUserInput();
const safeText = document.createTextNode(userInput);
document.getElementById('output').appendChild(safeText);

Quando você deve usar , higienizar com uma biblioteca

Se você precisa absolutamente renderizar HTML (por exemplo, de um editor de texto rico), confie em uma biblioteca de higienização confiável como DOMPURIFY. DOMPURIFY é uma biblioteca amplamente utilizada e testada em batalha que remove código malicioso enquanto preserva HTML seguro.

// Example with DOMPurify (install via npm or CDN)
const dirty = '<img src=x onerror="alert(1)">';
const clean = DOMPurify.sanitize(dirty);
document.getElementById('content').innerHTML = clean;

DOMPURIFY funciona processando a entrada, despindo tags e atributos perigosos e retornando apenas elementos permitidos. Ver DOMPURIFY no GitHub.

Evite funções perigosas do JavaScript

Alguns métodos e propriedades JavaScript são notórios para habilitar o XSS. Evite ou controle estritamente:

  • — use ou higienize corretamente.
  • , — mesma regra.
  • — nunca use com a entrada do usuário.
  • ] — pode ser explorado se qualquer entrada for concatenada.
  • / ] com código de texto — evite; use referências de função em vez disso.
  • ] construtor — análogo a ].

Implementar a Política de Segurança de Conteúdo (CSP) via JavaScript? Não Recomendado

O CSP é um mecanismo de navegador que restringe os scripts que podem ser executados. Ele é normalmente definido através de cabeçalhos HTTP, mas você também pode defini- lo usando uma tag ] ou via JavaScript criando dinamicamente um elemento . No entanto, definir o CSP no JavaScript é menos seguro porque um atacante que já tenha algum controle poderia desativá- lo. Sempre prefira o cabeçalho HTTP. Se você precisa usar o JavaScript para fazer cumprir o CSP (por exemplo, durante o desenvolvimento), faça- o muito cedo na carga da página:

const meta = document.createElement('meta');
meta.httpEquiv = 'Content-Security-Policy';
meta.content = "default-src 'self'; script-src 'self' 'unsafe-inline'"; // Be very careful with 'unsafe-inline'
document.head.appendChild(meta);

Para produção, configure CSP em seu servidor web ou proxy reverso. A documentação CSP do MDN fornece orientação abrangente.

Medidas de segurança adicionais

Além de táticas específicas do JavaScript, uma estratégia completa de prevenção do XSS inclui essas medidas críticas:

  • Sempre valida no lado do servidor. A validação do lado do cliente pode ser contornada. Nunca confie nos dados do cliente.
  • Use cabeçalhos de resposta HTTP apropriados. , , e especialmente .
  • Output codifica cada vez que você renderiza dados do usuário. Contexto importa: codificar para entidades HTML, codificação de URL, codificação de string JavaScript, etc.
  • Mantenha as dependências atualizadas. Bibliotecas JavaScript vulneráveis (por exemplo, versões mais antigas do jQuery) são um vetor XSS comum. Use a auditoria npm ou ferramentas semelhantes.
  • Use frameworks com proteção XSS incorporada. Reagir, Angular e Vue escapam automaticamente da saída por padrão. Ainda assim, seja cauteloso com ] ou .
  • Implementar um CSP rigoroso. Evite e se possível. Use nonces ou hashes para scripts em linha.

Exemplo do mundo real: Renderização segura do comentário

Considere um sistema de comentários do blog onde os usuários enviam mensagens que são exibidas para outros. Um atacante pode tentar inserir . Aqui está uma abordagem JavaScript que se integra com a infra-estrutura:

  1. Submissão de frontend: Sanitar usando antes de enviar para o servidor (mas o servidor ainda deve higienizar).
  2. Server retorna dados: A infraestrutura deve codificar HTML o texto do comentário.
  3. Reprodução de client: Use ou um motor de modelo seguro. Nunca use com dados de usuário brutos.
function renderComment(comment) {
 const item = document.createElement('div');
 item.className = 'comment';
 const body = document.createElement('p');
 body.textContent = comment.body; // escaped by browser
 item.appendChild(body);
 document.getElementById('comments').appendChild(item);
}

Teste de suas defesas

Após a implementação da prevenção, teste sua aplicação usando scanners automatizados e cargas manuais. Os vetores de teste comuns incluem:

Use ferramentas de desenvolvimento do navegador para examinar o DOM e garantir que as cargas úteis sejam escapadas. Além disso, teste a aplicação de CSP verificando o console para relatórios de violação.

Conclusão

O script de Cross-Site continua sendo uma ameaça séria, mas o JavaScript oferece ferramentas poderosas para detecção e prevenção. Ao validar entradas, monitorar mudanças de DOM, escapar de saída e integrar-se com bibliotecas robustas como DOMPURIFY, você pode endurecer significativamente a segurança do lado do cliente. Lembre-se que as medidas do lado do cliente não são uma bala de prata; elas complementam uma estratégia de defesa em profundidade que inclui higienização do lado do servidor, cabeçalhos CSP e auditorias de segurança regulares.

Para mais informações, consultar a página do OWASP XSS e a folha do OWASP XSS para a prevenção da fraude.