Cross-Site Request Forgeries e o senhor

À medida que a Web se torna cada vez mais difundida, o mesmo acontece com as vulnerabilidades de segurança baseadas na Web. Falei um pouco sobre a vulnerabilidade mais comum da Web, o cross-site scripting, em Protegendo seus cookies: HttpOnly. Embora o XSS seja incrivelmente perigoso, é um exploit bastante simples de entender. Não permita que os usuários insiram HTML arbitrário em seu site. O nome do jogo XSS é sanitizar a entrada do usuário. Se o senhor se ater a uma abordagem baseada em listas brancas — somente permita entradas que o senhor sabe que são boas, e imediatamente descarte todo o resto e, então, o senhor estará no caminho certo para resolver qualquer problema de XSS que possa ter.

Pensei que tínhamos resolvido as vulnerabilidades de nosso site com XSS. Eu estava errado. Steve Sanderson explica:

Como o XSS recebe todos os holofotes, poucos desenvolvedores prestam muita atenção a outra forma de ataque que é igualmente destrutiva e potencialmente muito mais fácil de ser explorada. Seu aplicativo pode estar vulnerável a ataques de falsificação de solicitações entre sites (CSRF) não porque o desenvolvedor tenha feito algo errado (por exemplo, deixar de codificar as saídas leva ao XSS), mas simplesmente porque toda a Web foi projetada para funcionar. Assustador!

Acontece que eu não entendia como o falsificação de solicitação entre sites, também conhecida como XSRF ou CSRF, funciona. Não é necessariamente complicado, mas é mais… sutil… do que o XSS.

Digamos que permitimos que os usuários publiquem imagens em nosso fórum. E se um de nossos usuários publicasse esta imagem?

<img src="http://foo.com/logout">

Não é realmente uma imagem, é verdade, mas forçará o URL de destino a ser recuperado por qualquer usuário aleatório que navegue nessa página — usando as credenciais do navegador! Do ponto de vista do servidor Web, não há diferença alguma entre uma solicitação do navegador iniciada por um usuário real e a recuperação do URL da imagem acima.

Se nossa página de logout fosse um simples HTTP GET que não exigisse confirmação, todos os usuários que visitassem essa página seriam imediatamente desconectados. Esse é o XSRF em ação. Não necessariamente perigoso, mas incômodo. Não é muito difícil imaginar versões muito mais destrutivas dessa técnica, não é mesmo?

Há duas maneiras óbvias de contornar esse tipo de ataque XSRF básico:

  1. Use um envio de formulário HTTP POST para fazer logout, e não um HTTP GET comum.
  2. Faça com que o usuário confirme o logout.

Solução fácil, certo? Provavelmente nunca deveríamos ter feito nenhuma dessas coisas em primeiro lugar. O senhor sabe!

Não tão rápido. Mesmo com as duas correções acima, o senhor está ainda vulnerável a ataques XSRF. Digamos que eu seguisse meu próprio conselho e convertesse o formulário de logout em um HTTP POST, com um grande botão intitulado “Log Me Out” confirmando a ação. O que impede um usuário mal-intencionado de colocar um formulário como esse em seu próprio site?

<body onload="document.getElementById('f').submit()">
<form id="f" action="http://foo.com/logout" method="post">
<input name="Log Me Out" value="Log Me Out" />
</form>
</body>

… e depois convencendo outros usuários a clicar nele?

Lembre-se de que o navegador agirá de bom grado de acordo com essa solicitação, enviando esse formulário juntamente com todos os cookies e credenciais necessários diretamente para o seu site. Que pena. O usuário foi desconectado. Exatamente como se o próprio usuário tivesse clicado no botão “Log Me Out”.

É claro que é preciso um pouco mais de engenharia social para convencer os usuários a visitar uma página da Web aleatória, mas não é muito. E as possibilidades de ataque são enormes: com o XSRF, os usuários mal-intencionados podem iniciar qualquer ação arbitrária que desejarem em um site-alvo. Tudo o que eles precisam fazer é enganar usuários incautos de o senhor que já têm um cookie de sessão de usuário validado armazenado no navegador, para que cliquem em seus links.

Então, o que podemos fazer para proteger nossos sites contra esses tipos de falsificação de solicitações entre sites?

  1. Verificar o referenciador. O referenciador HTTP, ou “referenciador” HTTP, como agora está permanentemente escrito de forma incorreta, deve sempre vir de seu próprio domínio. O senhor pode rejeitar qualquer post de formulário de referenciadores externos. No entanto, isso é arriscado, pois alguns proxies corporativos removem o referenciador de todas as solicitações HTTP como um recurso de anonimização. O senhor acabaria bloqueando usuários legítimos. Além disso, falsificar o valor do referenciador é extremamente fácil. Em suma, uma perda de tempo. Nem se preocupe com verificações de referenciador.
  2. Valor secreto do formulário oculto. Envie um valor de formulário de servidor exclusivo com cada formulário, normalmente vinculado à sessão do usuário, e valide se o senhor recebe o mesmo valor de volta na publicação do formulário. O invasor não pode simplesmente extrair seu formulário remoto como o usuário-alvo por meio do JavaScript, graças aos limites de solicitação do mesmo domínio no XmlHttpRequest .
  3. Cookies enviados duas vezes. É meio irônico, mas outra maneira de evitar o XSRF, essencialmente uma exploração baseada em cookies, é adicionar mais cookies! O envio duplo significa enviar o cookie nos dois sentidos em cada solicitação de formulário: primeiro como um valor de cabeçalho tradicional e, novamente, como um valor de formulário, lido via JavaScript e inserido. O truque aqui é que o XmlHttpRequest remotas não podem ler cookies. Se um dos valores não corresponder, descarte a entrada como falsa. A única desvantagem dessa abordagem é que ela exige que os usuários tenham o JavaScript ativado, caso contrário, seus próprios envios de formulário serão rejeitados.

Se o seu site é vulnerável ao XSRF, o senhor está em boa companhia. Digg, GMaile Wikipédia já foram atacados com sucesso dessa forma.

Talvez o senhor já esteja protegido contra o XSRF. Algumas estruturas da Web oferecem proteção integrada contra ataques XSRF, geralmente por meio de tokens de formulário exclusivos. Mas o senhor tem certeza disso? Não cometa o mesmo erro que eu! Entenda como o XSRF funciona e garanta que o senhor esteja protegido antes de isso se torne um problema.