Blog and Site, BETA!
Random header image... Refresh for more!

Ataque de Cross-Site Request Forgery, já ouviu falar?

Aposto que você ao menos já ouviu falar de XSS (Cross-Site Scripting), certo? Eu também. E de um tal de Cross-Site Request Forgery (CSRF, XSRF, session riding ou one-click attack [1])? Eu não! Caso você também não tenha ouvido falar ou lido a respeito, saiba: trata-se de uma técnica MUITO simples de ser explorada caso o seu site não esteja preparado para enfrentá-la. Quem já foi vítima? Digg, gmail, wikipedia, e-bay, entre outros.

Bem, eu dei uma garimpada na net sobre este ataque e resumo aqui as partes que considerei mais importantes (mais em [1] e [2]) e tento expor o problema de uma maneira palpável.

O Ataque

O que acontece quando você visita uma página que possui a seguinte tag?

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

O browser simplesmente não tem como saber, de antemão, se a URL da imagem especifica, de fato, uma imagem. Assim sendo, não tem como evitar: o browser vai requisitar seja-lá-o-que-for-que-esteja-especificado pelo atributo src da tag img.

Considere agora que a SUA aplicação realize operações sensíveis utilizando apenas a URL requisitada como parâmetro, não é muito difícil de imaginar esse tipo de situação, é? O exemplo mostra uma requisição de logout, mas coisas muito mais importantes, no contexto do sistema, podem ser requisitadas.

Aí você pode dizer: “Blz Zé, mas só um idiota faria isso sem que o usuário tenha se autenticado”. Eu concordo. Mas e se o usuário estiver autenticado? Suponha que ele tenha se autenticado e está com a sessão ativa. Em OUTRA aba do browser, o usuário acessa um fórum-da-vida. Qualquer um pode enviar qualquer tipo de imagem para um fórum-da-vida, lembra? E se esse qualquer um souber que o example.com não trata CSRF? Já era, você vai realizar requisições para o site em que você está logado sem nem sequer sonhar com isso. Se você acessar uma página que alguém (um atacante em potencial) te passou então, mais fácil ainda.

Como sanar o problema? Que tal realizar todas as requisições sensíveis através de POSTs? Apenas isto, também não funciona, basta ver o código abaixo, que pode estar em hospedado em um domínio diferente de example.com [2]:

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

Soluções

Como resolver, então? Bem, existem algumas soluções [2], vou citar apenas as com maior probabilidade de funcionar.

No lado do servidor (vítima do ataque, example.com, no exemplo acima), uma solução eficaz, facinho de implementar se você  usa o Zend Framework, por exemplo, é adicionar um valor aleatório em um campo escondido (input type=”hidden“) ao seu formulário que seja também armazenado na sessão. Assim, sempre que os dados do formulário forem processados será possível determinar se a submissão foi realmente gerada a partir da página criada por você, basta comparar o valor recebido do formulário com o armazenado na sessão. É isso, simples e eficaz.

E no lado do cliente? Tem jeito? Olha, ainda não testei, mas há algumas extensões para o firefox ([3], por exemplo) que prometem proteger o usuário. Tem que ser algo nesse sentido.

Condiderações Finais

Espero que o problema tenha ficado claro e que você pesquise mais sobre o tema, caso ainda não o tenha feito. Como foi visto, é muito simples de implementar o ataque uma vez que uma aplicação vulnerável tenha sido encontrada pelo atacante. É claro que para um ataque focado (em uma vítima especial) vai ser preciso uma boa dose de engenharia social por parte do atacante, mas no caso de aplicações populares a coisa fica mais fácil, né?

Algo a acrescentar?

[1] http://en.wikipedia.org/wiki/Cross-site_request_forgery

[2] http://www.codinghorror.com/blog/archives/001171.html

[3] https://addons.mozilla.org/en-US/firefox/addon/8996

May 31, 2009   No Comments