Cookies e gerenciamento de sessão
1. Fundamentos de Cookies no JavaScript
Cookies HTTP são pequenos arquivos de texto armazenados pelo navegador do usuário, contendo pares chave-valor que persistem entre requisições. Cada cookie possui atributos como domínio, path, data de expiração e flags de segurança.
Estrutura básica de um cookie:
nome=valor; Domain=exemplo.com; Path=/; Expires=Date; Secure; HttpOnly; SameSite=Lax
Lendo e escrevendo cookies com document.cookie
// Escrevendo um cookie simples
document.cookie = "usuario=joao; path=/; max-age=3600";
// Lendo todos os cookies
console.log(document.cookie); // "usuario=joao; preferencia=dark"
// Função para ler um cookie específico
function getCookie(nome) {
const cookies = document.cookie.split('; ');
for (const cookie of cookies) {
const [chave, valor] = cookie.split('=');
if (chave === nome) return decodeURIComponent(valor);
}
return null;
}
Atributos de segurança essenciais
// Cookie seguro com SameSite Strict
document.cookie = "token=abc123; Secure; SameSite=Strict; HttpOnly";
// Cookie com expiração personalizada
const dataExpiracao = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000);
document.cookie = `sessao=ativa; expires=${dataExpiracao.toUTCString()}; path=/`;
- Secure: Cookie enviado apenas via HTTPS
- HttpOnly: Inacessível via JavaScript (protege contra XSS)
- SameSite: Controla envio em requisições cross-site (Strict, Lax, None)
2. Gerenciamento de Cookies no Node.js (Backend)
Configuração com Express e cookie-parser
const express = require('express');
const cookieParser = require('cookie-parser');
const app = express();
app.use(cookieParser());
// Definindo cookie de resposta
app.post('/login', (req, res) => {
res.cookie('sessionId', 'sessao_123', {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'strict',
maxAge: 24 * 60 * 60 * 1000 // 24 horas
});
res.json({ mensagem: 'Login realizado' });
});
// Lendo cookies enviados pelo cliente
app.get('/perfil', (req, res) => {
const sessionId = req.cookies.sessionId;
if (!sessionId) return res.status(401).json({ erro: 'Não autenticado' });
res.json({ sessionId });
});
Opções avançadas com res.cookie()
app.get('/configurar-cookie', (req, res) => {
res.cookie('preferencia', 'dark-mode', {
domain: '.meusite.com', // Disponível em subdomínios
path: '/app', // Restrito à rota /app
expires: new Date('2025-12-31'),
signed: true // Cookie assinado para integridade
});
res.send('Cookie configurado');
});
3. Sessões no Servidor com Node.js
Sessões no servidor armazenam dados do usuário no backend, diferentemente de JWTs que são stateless. Isso oferece maior controle sobre revogação e segurança.
Implementação com express-session
const session = require('express-session');
app.use(session({
secret: 'chave-super-secreta',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: true,
maxAge: 1000 * 60 * 60 // 1 hora
}
}));
app.post('/login', (req, res) => {
// Autenticação simulada
req.session.userId = 123;
req.session.role = 'admin';
res.json({ mensagem: 'Sessão criada' });
});
app.get('/dashboard', (req, res) => {
if (!req.session.userId) {
return res.status(401).json({ erro: 'Faça login primeiro' });
}
res.json({ userId: req.session.userId, role: req.session.role });
});
Persistência com Redis (produção)
const RedisStore = require('connect-redis')(session);
const redis = require('redis');
const redisClient = redis.createClient();
app.use(session({
store: new RedisStore({ client: redisClient }),
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { httpOnly: true, secure: true, maxAge: 86400000 }
}));
4. Autenticação e Sessões no React (Frontend)
Envio automático de cookies com credentials: 'include'
// Configuração global do fetch
async function apiRequest(url, options = {}) {
const response = await fetch(`http://localhost:3001${url}`, {
...options,
credentials: 'include',
headers: {
'Content-Type': 'application/json',
...options.headers
}
});
return response.json();
}
// Login no React
async function handleLogin(email, senha) {
const data = await apiRequest('/login', {
method: 'POST',
body: JSON.stringify({ email, senha })
});
return data;
}
Gerenciamento de estado com Context API
const AuthContext = React.createContext();
function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Verificar sessão ao carregar
apiRequest('/verificar-sessao')
.then(data => setUser(data.user))
.catch(() => setUser(null))
.finally(() => setLoading(false));
}, []);
const login = async (email, senha) => {
const data = await handleLogin(email, senha);
setUser(data.user);
};
const logout = async () => {
await apiRequest('/logout', { method: 'POST' });
setUser(null);
};
return (
<AuthContext.Provider value={{ user, loading, login, logout }}>
{children}
</AuthContext.Provider>
);
}
5. Segurança em Cookies e Sessões
Proteção contra CSRF
// Backend - Geração de token CSRF
const crypto = require('crypto');
app.use((req, res, next) => {
if (!req.session.csrfToken) {
req.session.csrfToken = crypto.randomBytes(32).toString('hex');
}
res.cookie('csrf-token', req.session.csrfToken, { httpOnly: false, sameSite: 'strict' });
next();
});
// Middleware de validação CSRF
function csrfProtection(req, res, next) {
const tokenHeader = req.headers['x-csrf-token'];
if (tokenHeader !== req.session.csrfToken) {
return res.status(403).json({ erro: 'CSRF token inválido' });
}
next();
}
Prevenção contra XSS
// Frontend - Sanitização de entrada
function sanitizarInput(input) {
const div = document.createElement('div');
div.textContent = input;
return div.innerHTML;
}
// Backend - Headers de segurança
app.use((req, res, next) => {
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('X-Frame-Options', 'DENY');
res.setHeader('Content-Security-Policy', "default-src 'self'");
next();
});
6. Integração Completa: Exemplo Prático
Backend (Node.js + Express)
const express = require('express');
const session = require('express-session');
const bcrypt = require('bcrypt');
const app = express();
app.use(express.json());
app.use(session({
secret: process.env.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: { httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600000 }
}));
// Middleware de autenticação
function authMiddleware(req, res, next) {
if (!req.session.userId) return res.status(401).json({ erro: 'Não autorizado' });
next();
}
// Registro
app.post('/register', async (req, res) => {
const { email, senha } = req.body;
const hash = await bcrypt.hash(senha, 10);
// Salvar no banco...
res.json({ mensagem: 'Usuário criado' });
});
// Login
app.post('/login', async (req, res) => {
const { email, senha } = req.body;
// Verificar credenciais...
req.session.userId = 1;
res.json({ mensagem: 'Login bem-sucedido' });
});
// Rota protegida
app.get('/dados-protegidos', authMiddleware, (req, res) => {
res.json({ dados: 'Informação sensível' });
});
// Logout
app.post('/logout', (req, res) => {
req.session.destroy(err => {
if (err) return res.status(500).json({ erro: 'Erro ao fazer logout' });
res.clearCookie('connect.sid');
res.json({ mensagem: 'Logout realizado' });
});
});
Frontend (React)
function Login() {
const [email, setEmail] = useState('');
const { login } = useContext(AuthContext);
const handleSubmit = async (e) => {
e.preventDefault();
await login(email, 'senha123');
};
return (
<form onSubmit={handleSubmit}>
<input type="email" value={email} onChange={e => setEmail(e.target.value)} />
<button type="submit">Entrar</button>
</form>
);
}
function RotaProtegida() {
const { user, loading } = useContext(AuthContext);
if (loading) return <div>Carregando...</div>;
if (!user) return <Navigate to="/login" />;
return <div>Bem-vindo, {user.email}</div>;
}
Referências
- MDN Web Docs - HTTP cookies — Documentação completa sobre cookies HTTP, atributos de segurança e boas práticas
- Express.js - res.cookie() — Referência oficial da API Express para configuração de cookies no servidor
- express-session - npm — Pacote oficial para gerenciamento de sessões no Node.js com Express
- OWASP - Session Management Cheat Sheet — Guia de segurança para implementação de gerenciamento de sessão
- React - Context API — Documentação oficial do React sobre Context API para gerenciamento de estado global