Imagina que alguém engana um visitante para que clique num link enquanto ele tem sessão iniciada na conta do banco. Esse link leva a um formulário escondido que, sem o visitante saber, envia ao banco um pedido de transferência de dinheiro. O banco vê um pedido legítimo vindo de um utilizador autenticado e processa-o. O atacante moveu dinheiro através da conta da vítima sem nunca saber a palavra-passe.
É isto que é o CSRF (Cross-Site Request Forgery): um ataque em que o atacante engana uma vítima para que envie, sem querer, um formulário ou pedido a outro website onde a vítima já tem sessão iniciada.
O que vais aprender: o que são os ataques CSRF e como funcionam, porque são tão perigosos mesmo havendo outras medidas de segurança, como os tokens CSRF os impedem e como implementar a proteção nos teus formulários.
O que é o CSRF?
CSRF (pronuncia-se "sea-surf") significa Cross-Site Request Forgery. É um ataque em que o atacante explora o facto de, quando tens sessão iniciada num website, o navegador confiar automaticamente na tua sessão e incluí-la em todos os pedidos que fazes a esse site, mesmo que o pedido venha de um website diferente.
O ataque funciona enganando um visitante com sessão iniciada para que envie, sem saber, um formulário a um website onde tem conta. O atacante não consegue ver a palavra-passe da vítima. Não precisa. Só precisa que a vítima já tenha sessão iniciada e depois enganá-la para fazer um pedido (como enviar um formulário escondido) que faz o que o atacante quer.
O CSRF é diferente de outros ataques porque não exige roubar credenciais nem quebrar a encriptação. Explora a confiança da vítima no website. A vítima já está autenticada, por isso o website confia nos pedidos que parecem vir dela.
Como funcionam os ataques CSRF
Um ataque CSRF acontece em três passos.
Passo 1: A vítima tem sessão iniciada no teu site
Alguém visita o teu website e inicia sessão na sua conta. O navegador tem agora um cookie de sessão ativo que prova que a pessoa está autenticada. Esta sessão mantém-se ativa enquanto a pessoa continuar a usar o site.
Passo 2: O atacante engana-a para visitar uma página maliciosa
Ainda com sessão iniciada no teu site, a vítima visita uma página controlada pelo atacante (talvez um link das redes sociais, um anúncio enganador ou um website com ar legítimo). Nessa página há código escondido que envia um formulário de volta para o teu site.
Passo 3: O formulário é enviado automaticamente com a sessão da vítima
O formulário escondido é enviado para o teu website. Como a vítima já tem sessão iniciada, o navegador inclui automaticamente o cookie de sessão no pedido. Do ponto de vista do teu formulário, é um pedido legítimo de um utilizador autenticado. O formulário processa-o como se a vítima o tivesse enviado de propósito.
O atacante fez agora algo no teu site usando a conta da vítima, sem que ela saiba. Pode ter mudado a palavra-passe, transferido dinheiro, atualizado o perfil ou enviado dados.
Porque é que isto funciona mesmo com outras medidas de segurança
Os ataques CSRF contornam várias proteções comuns:
O HTTPS não impede o CSRF. Os dados vão encriptados durante o envio, mas o atacante não precisa de os intercetar. Só tem de enviar o pedido a partir do navegador da vítima, em que esse mesmo navegador já confia.
Proteger com palavra-passe não impede o CSRF. O atacante nunca precisa da palavra-passe da vítima. Só explora o facto de a vítima já ter sessão iniciada.
Um bom sistema de login não impede o CSRF. Mesmo que a autenticação seja perfeita, se a vítima tem sessão iniciada, o ataque funciona.
É por isso que a proteção CSRF é uma camada própria. Não é evitado por outras medidas de segurança. Tens de desenhar os formulários de propósito para resistirem aos ataques CSRF.
Tokens CSRF: como travam o ataque
A solução é um token CSRF. É uma sequência de caracteres única e imprevisível que o teu servidor gera para cada formulário. Funciona assim:
O teu servidor cria um token único para cada visitante
Quando alguém carrega uma página com um formulário, o servidor gera um token aleatório e associa-o à sessão desse utilizador. Este token é diferente de cada vez e é único para esse utilizador.
O token vem incluído no formulário
O token é incluído como um campo escondido no formulário HTML. Quando o visitante envia o formulário, o token vai com ele.
O teu servidor verifica o token antes de processar o envio
Quando o formulário é enviado, o servidor verifica se o token do envio corresponde ao token que gerou para a sessão desse utilizador. Se sim, o formulário é processado. Se não (ou se não houver token), o formulário é rejeitado.
O formulário escondido do atacante não consegue incluir um token válido, porque os tokens são imprevisíveis e únicos para cada sessão. Um atacante noutro domínio não consegue ver nem adivinhar o token. Por isso o ataque falha. O formulário escondido é enviado, mas o teu servidor rejeita-o porque o token não corresponde.
Como é um token CSRF na prática
Em HTML, um formulário protegido contra CSRF tem este aspeto:
<form method="POST" action="/submit-form"> <input type="hidden" name="csrf_token" value="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"> <input type="email" name="email" placeholder="Your email"> <button type="submit">Submit</button> </form> O campo `csrf_token` está escondido. O visitante não o vê, mas é enviado junto com os dados do formulário. O teu servidor verifica-o antes de processar o email ou quaisquer outros dados.
Proteção CSRF para diferentes tipos de formulário
Formulários HTML tradicionais
Os formulários HTML normais (os que enviam dados por POST para o teu servidor) precisam de tokens CSRF. Isto inclui formulários de contacto, de login, de recuperação de palavra-passe e qualquer formulário que altere dados no teu servidor.
Formulários AJAX e JavaScript
Os formulários enviados por JavaScript para um endpoint de API também precisam de proteção CSRF. O token pode ir no próprio formulário, ficar guardado num cookie ou ser obtido a partir de uma meta tag antes de o pedido ser enviado.
Pedidos de API sem estado
Se a tua API usa autenticação baseada em tokens (como JWT), a proteção CSRF funciona de outra forma. O navegador não consegue anexar automaticamente um token JWT como anexa um cookie de sessão, por isso o CSRF tradicional é uma ameaça menor. Mesmo assim, a boa prática continua a ser incluir um token CSRF adicional para mais proteção.
Outras proteções que funcionam com os tokens CSRF
Os tokens CSRF são a defesa principal, mas funcionam melhor em conjunto com outras práticas de segurança.
Cookies SameSite
Ao definir um cookie de sessão, podes acrescentar um atributo `SameSite` que diz ao navegador para não incluir o cookie quando os pedidos vêm de um domínio diferente. Assim, o formulário escondido do atacante nem chega a usar a sessão da vítima.
Verificação do cabeçalho Referer
O teu servidor pode verificar o cabeçalho Referer para ver de onde veio o pedido. Se um envio de formulário diz vir do teu domínio mas o Referer mostra um domínio diferente, provavelmente é um ataque. (No entanto, os cabeçalhos Referer podem ser falsificados, por isso esta não é uma defesa completa.)
Padrão de cookie de envio duplo
Nesta abordagem, o token CSRF fica guardado num cookie e num campo do formulário. O teu servidor verifica se coincidem antes de processar. É menos comum do que os tokens tradicionais, mas funciona bem em aplicações sem estado.
Como implementar a proteção CSRF
Os detalhes da implementação dependem da tua stack tecnológica, mas o padrão é o mesmo:
- Gera um token único por sessão. Quando um utilizador inicia uma sessão ou carrega uma página com formulário, o teu backend gera um novo token.
- Guarda o token no servidor. Guarda-o associado à sessão desse utilizador.
- Inclui o token no formulário. Acrescenta-o como campo escondido no HTML ou como meta tag que o JavaScript possa ler.
- Valida no envio. Antes de processar qualquer dado do formulário, verifica se o token enviado corresponde ao token guardado para essa sessão.
- Gera de novo depois de ações sensíveis. Depois de um utilizador mudar a palavra-passe ou fazer algo crítico, gera um novo token.
A maioria dos frameworks modernos (de Python, Ruby, PHP e .NET) trata a geração e a validação dos tokens CSRF automaticamente. Se usas um framework, a proteção CSRF costuma vir ativa por defeito. Só tens de garantir que não a desativas sem querer.
Erros comuns que deixam os formulários vulneráveis
Desativar a proteção CSRF por comodidade. Alguns programadores desligam as verificações CSRF para facilitar os testes da API ou simplificar o código. Não faças isto. Cria uma vulnerabilidade real.
Usar um token estático para todos os utilizadores. O token tem de ser único para a sessão de cada utilizador. Um token igual para toda a gente (ou igual para todos os utilizadores em todos os dias) não protege contra o CSRF.
Não gerar tokens de novo. Se usas o mesmo token durante semanas, o atacante tem mais tempo para o explorar. Gera os tokens de novo com regularidade e sempre depois de operações sensíveis.
Depender só de cookies SameSite. O SameSite ajuda, mas não chega. Usa os tokens CSRF como defesa principal e o SameSite como reserva.
Esquecer os tokens em alguns formulários. Se proteges alguns formulários com tokens e outros não, os atacantes vão usar os desprotegidos. Todos os formulários que alteram dados precisam de proteção.
O que a WEMASY faz pela proteção CSRF
Os formulários da WEMASY incluem automaticamente a proteção por token CSRF em todos os formulários que crias. Não precisas de a configurar nem de pensar nisso. Quando um visitante envia um formulário, a WEMASY valida o token antes de guardar o envio. Esta proteção vem integrada e ativa por defeito.
Descobre mais sobre as opções de segurança dos formulários na página de preços.