Entendendo Sessões e Cookies em PHP
Sessões e cookies são os pilares da autenticação stateful na web. Um cookie é um pequeno arquivo armazenado no navegador do cliente que persiste entre requisições, enquanto uma sessão é um mecanismo servidor-side que mantém dados do usuário em memória ou banco de dados. A diferença crucial: cookies são visíveis e modificáveis pelo cliente; sessões são seguras, pois residem no servidor.
Em PHP, quando você cria uma sessão, um identificador único (Session ID) é gerado e armazenado em um cookie no navegador. A cada requisição, esse cookie é enviado automaticamente, permitindo que o servidor recupere os dados da sessão correspondente. Esse padrão é chamado autenticação stateful — o servidor mantém o estado da autenticação.
Implementando Sessões Seguras
Iniciando e Usando Sessões
<?php
// Sempre no início do arquivo, antes de qualquer output
session_start();
// Configurações de segurança (PHP 7.1+)
session_set_cookie_params([
'lifetime' => 3600, // 1 hora
'path' => '/',
'domain' => 'exemplo.com',
'secure' => true, // HTTPS apenas
'httponly' => true, // Sem acesso via JavaScript
'samesite' => 'Strict' // Proteção contra CSRF
]);
// Verificar se o usuário está autenticado
if (!isset($_SESSION['user_id'])) {
header('Location: login.php');
exit;
}
echo "Bem-vindo, " . htmlspecialchars($_SESSION['username']);
?>
Esses parâmetros são essenciais: httponly impede ataques XSS (Cross-Site Scripting), secure força HTTPS, e samesite previne CSRF (Cross-Site Request Forgery). Nunca ignore essas configurações em produção.
Autenticação com Hash de Senha
<?php
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
// Simular busca no banco de dados
$user = [
'id' => 1,
'username' => 'joao',
'password_hash' => password_hash('senha123', PASSWORD_BCRYPT)
];
if ($username === $user['username'] &&
password_verify($password, $user['password_hash'])) {
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['created_at'] = time();
header('Location: dashboard.php');
exit;
} else {
$error = "Credenciais inválidas";
}
}
?>
<form method="POST">
<input type="text" name="username" required>
<input type="password" name="password" required>
<button type="submit">Entrar</button>
</form>
<?php if (isset($error)): ?>
<p><?php echo htmlspecialchars($error); ?></p>
<?php endif; ?>
Nunca armazene senhas em texto plano. Use password_hash() com o algoritmo BCRYPT para hash e password_verify() para validação. Isso é o padrão ouro de segurança.
Trabalhando com Cookies Explicitamente
Quando Usar Cookies ao Invés de Sessões
Cookies são ideais para dados não-sensíveis que devem persistir além da sessão. Um exemplo comum: preferências de idioma ou tema visual. Nunca coloque IDs de usuário ou tokens diretamente em cookies sem proteção.
<?php
// Definir um cookie seguro
setcookie(
'idioma', // nome
'pt-BR', // valor
[
'expires' => time() + (365 * 24 * 60 * 60), // 1 ano
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]
);
// Acessar cookie
$idioma = $_COOKIE['idioma'] ?? 'pt-BR';
// Deletar cookie
setcookie('idioma', '', ['expires' => time() - 3600]);
?>
Note que setcookie() deve ser chamado antes de qualquer output. Use a sintaxe de array para setcookie() (PHP 7.3+), pois é mais legível e segura.
Segurança e Manutenção de Sessões
Regeneração de Session ID
Um ataque comum é a fixação de sessão. Um atacante tenta forçar o usuário a usar um Session ID conhecido. A defesa é regenerar o ID após login:
<?php
session_start();
// Após validar credenciais (no login)
session_regenerate_id(true); // true = destruir sessão antiga
$_SESSION['user_id'] = $user['id'];
// Validar idade da sessão (logout automático)
$tempo_inatividade = 30 * 60; // 30 minutos
$tempo_atual = time();
if (isset($_SESSION['created_at'])) {
if ($tempo_atual - $_SESSION['created_at'] > $tempo_inatividade) {
session_destroy();
header('Location: login.php?timeout=1');
exit;
}
}
// Logout
if (isset($_GET['logout'])) {
session_destroy();
header('Location: index.php');
exit;
}
?>
A regeneração de ID impede ataques de fixação. O timeout automático protege contra sessões abandonadas em computadores públicos — uma prática essencial.
Armazenamento Seguro de Sessão
Por padrão, PHP armazena sessões em arquivos. Para aplicações grandes ou com múltiplos servidores, use banco de dados:
<?php
session_start();
class SessionHandler extends SessionHandlerInterface {
private $pdo;
public function __construct(\PDO $pdo) {
$this->pdo = $pdo;
}
public function read($id) {
$stmt = $this->pdo->prepare(
'SELECT data FROM sessions WHERE id = ? AND expires > ?'
);
$stmt->execute([$id, time()]);
$result = $stmt->fetch();
return $result ? $result['data'] : '';
}
public function write($id, $data) {
$stmt = $this->pdo->prepare(
'INSERT INTO sessions (id, data, expires) VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE data = ?, expires = ?'
);
return $stmt->execute([$id, $data, time() + 3600, $data, time() + 3600]);
}
public function destroy($id) {
return $this->pdo->prepare('DELETE FROM sessions WHERE id = ?')
->execute([$id]);
}
// Outros métodos obrigatórios...
public function open($path, $name) { return true; }
public function close() { return true; }
public function gc($max_lifetime) {
return $this->pdo->prepare('DELETE FROM sessions WHERE expires < ?')
->execute([time()]);
}
}
// Usar o handler customizado
$handler = new SessionHandler($pdo);
session_set_save_handler($handler);
session_start();
?>
Banco de dados oferece melhor controle, escalabilidade e facilita limpeza automática de sessões expiradas.
Conclusão
Sessões e cookies formam a base da autenticação web. O aprendizado principal: use sessões para dados sensíveis, proteja com HTTPS, regenere IDs e defina timeouts. Cookies são complementares para dados não-críticos. Sempre implemente httponly, secure e samesite para mitigar os principais vetores de ataque (XSS, CSRF, man-in-the-middle). Em produção, armazene sessões em banco de dados e monitore expiração.