A injeção de SQL ataca o banco de dados do site. O cross-site scripting, o XSS, ataca outra coisa: o navegador de quem usa o site. É uma das falhas mais comuns em aplicação web, e uma das mais mal compreendidas, porque a vítima não é o servidor, é o outro usuário.
Já falei da injeção de SQL em Injeção de SQL. O XSS é primo dela: nasce do mesmo erro de não separar dado de código, só que do lado do navegador.
De onde vem a falha
Um site com XSS aceita um texto de um usuário e o exibe para outros sem tratar. Se esse texto contém código de navegador em vez de texto comum, o navegador de quem vê a página executa esse código, achando que faz parte do site.
O navegador confia no que vem do site. Se o site deixa um usuário injetar código que chega até outro usuário, essa confiança é traída. O código roda com os privilégios do site na sessão da vítima, e é aí que mora o perigo.
Os tipos de XSS
| Tipo | Como funciona |
|---|---|
| Refletido | O código vai numa requisição e volta na resposta. A vítima precisa clicar num link preparado. |
| Armazenado | O código fica salvo no site, num comentário ou perfil, e atinge todo mundo que vê aquela página. |
| No navegador | A falha está no próprio código que roda no navegador, ao manipular a página de forma insegura. |
O armazenado é o mais grave. Um comentário malicioso salvo numa página muito visitada atinge cada visitante, sem precisar enganar ninguém para clicar em nada.
O que um atacante consegue
Executando código no navegador da vítima, dentro da sessão dela no site, o atacante pode:
- Roubar o cookie de sessão, e com ele assumir a conta da vítima sem saber a senha.
- Agir em nome da vítima, fazendo o que ela poderia fazer no site.
- Alterar o que a vítima vê, montando telas falsas para capturar dados.
- Redirecionar para páginas maliciosas.
O roubo do cookie de sessão é o mais explorado. É por isso que a proteção do cookie, que discuti a propósito de tráfego em claro, importa tanto: o XSS é mais uma via para chegar até ele.
Como testar, com autorização
Em teste autorizado, o primeiro sinal de XSS aparece ao inserir um texto simples e inofensivo com caracteres de marcação em campos que são exibidos de volta, e observar se o navegador o interpreta como código em vez de texto.
# um teste inofensivo: o site exibe isto como TEXTO ou executa?
# se o alerta aparecer, o campo nao trata a entrada = candidato a XSS
<script>alert(1)</script>A regra do teste é a de sempre: prova sem dano. Confirmar que o navegador executa a entrada e parar. Um alerta simples demonstra a falha sem causar prejuízo, e é suficiente para o relatório.
A correção: tratar a saída
A raiz do XSS é exibir a entrada do usuário sem tratá-la. A correção, portanto, é tratar sempre a saída. Isso se chama codificar a saída: antes de mostrar um texto que veio do usuário, converter os caracteres especiais para que o navegador os exiba como texto, nunca os interprete como código.
Feito isso, o mesmo texto que antes virava código passa a aparecer literalmente na tela, inofensivo. A distinção entre dado e código, que a aplicação vulnerável perdeu, é restaurada no ponto de exibição.
Camadas de apoio
- Validar a entrada pelo formato esperado, como reforço, nunca como defesa única.
- Proteger o cookie de sessão para que o código no navegador não consiga lê-lo, o que reduz o impacto mesmo se um XSS passar.
- Usar uma política que restrinja de onde o navegador pode carregar e executar código na página.
Por que continua comum
Como a injeção de SQL, o XSS é conhecido há anos e a correção é bem estabelecida. E, como ela, continua aparecendo em toda parte, porque cada ponto onde a aplicação exibe algo que veio do usuário é uma oportunidade de esquecer de tratar a saída. Basta um campo esquecido.
Fechar o XSS de verdade não é aplicar uma correção única; é adotar a disciplina de tratar toda saída, em todo ponto, como regra da casa. É trabalhoso e é o que separa a aplicação que resiste da que expõe seus usuários.