O que é CSRF e por que se preocupar?

Ataques CSRF (Cross-Site Request Forgery) representam uma ameaça significativa para aplicações web, explorando a confiança que um navegador deposita em um site autenticado. Em essência, um ataque CSRF induz um usuário autenticado a executar uma ação indesejada em uma aplicação web na qual ele está logado. O ataque explora a maneira como os navegadores lidam com cookies de autenticação e sessões. Quando um usuário está logado em um site, o navegador automaticamente envia os cookies de autenticação com cada requisição para aquele domínio. Um atacante pode criar uma página maliciosa, um link em um e-mail, ou explorar uma vulnerabilidade em outro site para fazer com que o navegador do usuário envie uma requisição para o site vulnerável. Se a aplicação não tiver proteções adequadas, essa requisição será executada como se tivesse sido iniciada pelo próprio usuário legítimo.

Imagine a seguinte situação: você está logado no seu banco online. Em outra aba do navegador, você visita um site que você não conhece. Esse site malicioso contém um código que, ao ser carregado, tenta fazer uma transferência bancária para uma conta controlada pelo atacante. Se o seu banco online não estiver protegido contra CSRF, o seu navegador enviará automaticamente seus cookies de autenticação junto com a requisição de transferência, e o banco executará a operação. A gravidade reside no fato de que o ataque não rouba credenciais, mas sim abusa da autenticação já estabelecida para executar ações maliciosas.

Mecanismos de Defesa Contra CSRF

A proteção contra CSRF geralmente envolve a implementação de um token único e imprevisível que é associado à sessão do usuário e enviado com cada requisição que modifica o estado do servidor (como POST, PUT, DELETE). O servidor, então, valida a presença e a validade desse token. Se o token estiver ausente ou for inválido, a requisição é rejeitada.

1. Tokens Anti-CSRF (Synchronizer Token Pattern)

Este é o método mais comum e eficaz. Ele funciona da seguinte forma:

  • Quando um usuário faz login ou inicia uma sessão, o servidor gera um token anti-CSRF único e imprevisível.
  • Esse token é armazenado no lado do servidor, geralmente associado à sessão do usuário.
  • O token também é enviado ao cliente (navegador), geralmente incorporado em um campo oculto em formulários HTML. Para aplicações SPA (Single Page Application), o token pode ser enviado via cookie ou em uma resposta da API e armazenado no frontend (por exemplo, em memória ou localStorage, com devidas precauções de segurança).
  • Quando o cliente envia uma requisição que modifica o estado do servidor (por exemplo, um POST para criar um post, um PUT para atualizar um perfil), o token é incluído na requisição. Para formulários tradicionais, ele é enviado como um parâmetro do formulário. Para APIs, ele pode ser enviado no cabeçalho da requisição (como X-CSRF-Token) ou como parte do corpo da requisição.
  • O servidor verifica se o token recebido na requisição corresponde ao token armazenado para a sessão do usuário. Se houver uma correspondência, a requisição é considerada legítima e processada. Caso contrário, a requisição é rejeitada com um erro (geralmente 403 Forbidden).

A chave para a segurança aqui é que um atacante, sem acesso à sessão do usuário, não pode obter ou adivinhar o token correto para incluir em suas requisições maliciosas. O token deve ser gerado de forma segura, ser único por sessão (ou até por requisição, em cenários de alta segurança), e nunca deve ser transmitido de forma insegura.

Diagrama ilustrando o fluxo de autenticação e validação de token anti-CSRF

2. Verificação do Cabeçalho Referer e Origin

Os cabeçalhos Referer e Origin podem fornecer informações sobre a origem da requisição. O cabeçalho Referer indica a URL da página que originou a requisição, enquanto Origin especifica o domínio que iniciou a requisição. O servidor pode verificar se esses cabeçalhos contêm um domínio confiável. No entanto, esses cabeçalhos não são totalmente confiáveis:

  • O cabeçalho Referer pode ser omitido por configurações de privacidade do navegador ou por proxies.
  • O cabeçalho Origin é mais confiável, mas ainda pode ser manipulado em certos cenários.

Por essas razões, a verificação desses cabeçalhos é geralmente usada como uma camada adicional de defesa, e não como o único mecanismo de proteção.

3. SameSite Cookies

Os atributos SameSite para cookies, introduzidos pelo Google Chrome e posteriormente adotados por outros navegadores, oferecem uma proteção robusta contra CSRF. Eles controlam quando os cookies são enviados em requisições entre sites.

  • Strict: O cookie só é enviado em requisições originadas do mesmo site. Isso oferece a proteção mais forte, mas pode quebrar fluxos de navegação legítimos (por exemplo, clicar em um link de e-mail para um site autenticado).
  • Lax: O cookie é enviado em requisições do mesmo site e em navegações de nível superior (top-level navigations) que usam métodos GET. É um bom equilíbrio entre segurança e usabilidade, sendo o padrão em muitos navegadores modernos.
  • None: O cookie é enviado em todas as requisições, tanto do mesmo site quanto entre sites. Requer o atributo Secure (o cookie só é enviado em conexões HTTPS). Usado para cenários onde cookies de terceiros são necessários.

Configurar seus cookies de sessão com SameSite=Lax ou SameSite=Strict pode mitigar a maioria dos ataques CSRF, pois impede que o navegador envie o cookie de autenticação em requisições maliciosas iniciadas de outros sites.

Considerações para Aplicações Frontend

Para aplicações construídas com frameworks modernos de frontend como React, Vue ou Angular, a implementação de tokens anti-CSRF requer uma abordagem cuidadosa, especialmente ao interagir com APIs RESTful.

  • Gerenciamento de Tokens: O token pode ser obtido do servidor via um endpoint dedicado ou incluído em um cookie HTTP-only (com atributo SameSite=Lax). Se armazenado no cliente (localStorage, sessionStorage), é crucial garantir que não seja vulnerável a ataques XSS, pois um atacante que consiga injetar script pode roubar o token.
  • Requisições AJAX/Fetch: Ao fazer requisições assíncronas (AJAX, Fetch API), o token deve ser incluído nos cabeçalhos da requisição (ex: X-CSRF-Token). Frameworks de backend e bibliotecas de frontend frequentemente oferecem suporte integrado para isso.
  • Autenticação Baseada em Token (JWT): Se sua aplicação usa autenticação baseada em token (como JWT), onde o token é enviado no cabeçalho Authorization, a proteção contra CSRF é inerentemente diferente. Como o token não é gerenciado automaticamente pelo navegador como cookies, um atacante não pode forçar o navegador a enviar um token JWT em uma requisição cross-site. No entanto, é crucial que o token JWT não seja armazenado em cookies. Armazená-lo no localStorage ou sessionStorage, e incluí-lo explicitamente em cada requisição via cabeçalho Authorization, protege contra CSRF.

Conclusão

Proteger sua aplicação frontend contra ataques CSRF é uma etapa fundamental na segurança web. A implementação do padrão Synchronizer Token Pattern, combinado com o uso de SameSite cookies, oferece uma defesa robusta. Para SPAs e APIs, é essencial entender como gerenciar e transmitir tokens de forma segura, e considerar o modelo de autenticação utilizado. A vigilância contínua e a adoção das melhores práticas de segurança garantem a integridade e a confiança dos seus usuários.