Capítulo 5.4: Trabalhando com Tokens CSRF
Tempo de estudo: 30 minutos
1. O que é um ataque CSRF? O "Sequestro" da sua nave
Imagine que você está logado no painel de controle da sua frota espacial (space-api.test
). Em uma aba vizinha, você abre um site inofensivo de gatinhos (evil-cats.com
). Neste site, há um formulário oculto que envia automaticamente uma requisição para o seu site no endereço POST /api/planets/1/delete
.
Como você já está autenticado em space-api.test
, seu navegador gentilmente anexará todos os seus cookies a essa requisição. O servidor Laravel verá uma sessão válida e pensará que foi você quem decidiu desativar o planeta. O planeta será excluído sem o seu conhecimento.
Isso é CSRF (Cross-Site Request Forgery) — um ataque no qual um invasor força o navegador de um usuário autenticado a executar uma ação indesejada em um site confiável.
💡 Analogia espacial:
Você é o capitão da nave e tem um cartão-chave (sessão/cookie). O invasor não pode roubar seu cartão. Mas ele pode, por engano, fazer você passá-lo em um terminal de descarte de recursos enquanto você está distraído. O token CSRF é como um código PIN que precisa ser inserido junto com o cartão. O invasor não sabe o código PIN, e seu ataque falha.
2. Como o Laravel protege contra CSRF?
Por padrão, o Laravel protege todas as requisições web "inseguras" (POST, PUT, PATCH, DELETE) usando um token CSRF.
- Ao gerar uma página, o Laravel cria um token único e aleatório para a sessão do usuário.
- Este token é incorporado nos formulários HTML.
- Ao enviar o formulário, o token é enviado junto com a requisição.
- No servidor, o middleware
VerifyCsrfToken
compara o token da requisição com o token armazenado na sessão. - Se os tokens não coincidirem, o Laravel interrompe a requisição com um erro 419 (Sessão Expirada/Página Expirada).
Importante: As rotas de API em routes/api.php
não são protegidas por CSRF, pois elas presumem um mecanismo de autenticação diferente (por exemplo, tokens Sanctum), e não sessões baseadas em cookies. Nosso problema atual refere-se especificamente às rotas web e páginas que criamos em routes/web.php
.
3. Usando o Token CSRF em Formulários HTML
Este é o cenário mais simples. O Laravel fornece uma diretiva Blade especial para isso.
Exemplo: Formulário para criar um planeta
Vamos criar um formulário simples no arquivo resources/views/planets/create.blade.php
:
<h2>Formulário para Lançamento de um Novo Planeta</h2>
<form action="/planets" method="POST">
@csrf {{-- Aqui está a mágica! --}}
<label for="name">Nome:</label>
<input type="text" id="name" name="name" required>
<label for="solar_system">Sistema Solar:</label>
<input type="text" id="solar_system" name="solar_system" required>
{{-- ... outros campos ... --}}
<button type="submit">Lançar</button>
</form>
A diretiva @csrf
gerará automaticamente um campo oculto no formulário:
Isso é suficiente para proteger formulários HTML padrão.
4. Usando o Token CSRF em Requisições AJAX/Fetch
No capítulo anterior, enviamos uma requisição DELETE
usando JavaScript. Agora, o Laravel a bloqueará com um erro 419. Precisamos adicionar o token CSRF aos cabeçalhos da nossa requisição Fetch.
Passo 1: Tornar o token disponível para JavaScript
Adicione uma meta tag com o token na <head>
do seu layout mestre resources/views/app.blade.php
. Esta é uma prática padrão no Laravel.
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
{{-- Adicionamos o token CSRF na meta tag --}}
<meta name="csrf-token" content="{{ csrf_token() }}">
{{-- ... --}}
</head>
A função csrf_token()
retorna o token atual.
Passo 2: Modificar o JavaScript para enviar o token
Agora, em nosso public/js/planets.js
, podemos ler este token e adicioná-lo aos cabeçalhos de todas as requisições "inseguras".
// ... no arquivo public/js/planets.js ...
document.addEventListener('DOMContentLoaded', () => {
// Obtenha o token da meta tag
const csrfToken = document.querySelector('meta[name="csrf-token"]').getAttribute('content');
const deleteButtons = document.querySelectorAll('.delete-btn');
deleteButtons.forEach(button => {
button.addEventListener('click', async (event) => {
// ... lógica de confirmação ...
try {
const response = await fetch(apiUrl, {
method: 'DELETE',
headers: {
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken // <-- Adicionamos o token nos cabeçalhos!
}
});
// ... o resto da lógica de processamento da resposta ...
} catch (error) {
// ...
}
});
});
});
- O nome do cabeçalho
X-CSRF-TOKEN
é um padrão que o Laravel verifica por padrão.
Agora nossas requisições AJAX também estão protegidas. Tente excluir um planeta novamente — desta vez, a requisição será bem-sucedida.
Questionário para Fixação
🚀 Resumo do Capítulo:
Você instalou um "sistema de identificação amigo ou inimigo" em sua nave espacial, protegendo-a de ataques CSRF. Você aprendeu a:
- Compreender a natureza e o perigo dos ataques CSRF.
- Proteger formulários HTML padrão usando a diretiva
@csrf
. - Passar o token CSRF para JavaScript via meta tag.
- Incluir o token nos cabeçalhos de requisições AJAX/Fetch para sua execução bem-sucedida.
Suas interfaces web agora não são apenas interativas, mas também seguras. No próximo capítulo, concluiremos a criação de nossa interface web, abordando como organizar corretamente o roteamento para páginas web.