<h2>Entendendo Sessões e Cookies em PHP</h2>
<p>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.</p>
<p>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 <strong>autenticação stateful</strong> — o servidor mantém o estado da autenticação.</p>
<h2>Implementando Sessões Seguras</h2>
<h3>Iniciando e Usando Sessões</h3>
<pre><code class="language-php"><?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']);
?></code></pre>
<p>Esses parâmetros são essenciais: <code>httponly</code> impede ataques XSS (Cross-Site Scripting), <code>secure</code> força HTTPS, e <code>samesite</code> previne CSRF (Cross-Site Request Forgery). Nunca ignore essas configurações em produção.</p>
<h3>Autenticação com Hash de Senha</h3>
<pre><code class="language-php"><?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; ?></code></pre>
<p>Nunca armazene senhas em texto plano. Use <code>password_hash()</code> com o algoritmo BCRYPT para hash e <code>password_verify()</code> para validação. Isso é o padrão ouro de segurança.</p>
<h2>Trabalhando com Cookies Explicitamente</h2>
<h3>Quando Usar Cookies ao Invés de Sessões</h3>
<p>Cookies são ideais para dados <strong>não-sensíveis</strong> 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.</p>
<pre><code class="language-php"><?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]);
?></code></pre>
<p>Note que <code>setcookie()</code> deve ser chamado <strong>antes</strong> de qualquer output. Use a sintaxe de array para <code>setcookie()</code> (PHP 7.3+), pois é mais legível e segura.</p>
<h2>Segurança e Manutenção de Sessões</h2>
<h3>Regeneração de Session ID</h3>
<p>Um ataque comum é a <strong>fixação de sessão</strong>. Um atacante tenta forçar o usuário a usar um Session ID conhecido. A defesa é regenerar o ID após login:</p>
<pre><code class="language-php"><?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;
}
?></code></pre>
<p>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.</p>
<h3>Armazenamento Seguro de Sessão</h3>
<p>Por padrão, PHP armazena sessões em arquivos. Para aplicações grandes ou com múltiplos servidores, use banco de dados:</p>
<pre><code class="language-php"><?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();
?></code></pre>
<p>Banco de dados oferece melhor controle, escalabilidade e facilita limpeza automática de sessões expiradas.</p>
<h2>Conclusão</h2>
<p>Sessões e cookies formam a base da autenticação web. O aprendizado principal: <strong>use sessões para dados sensíveis, proteja com HTTPS, regenere IDs e defina timeouts</strong>. Cookies são complementares para dados não-críticos. Sempre implemente <code>httponly</code>, <code>secure</code> e <code>samesite</code> 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.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://www.php.net/manual/en/book.session.php" target="_blank" rel="noopener noreferrer">Documentação Oficial do PHP - Sessions</a></li>
<li><a href="https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html" target="_blank" rel="noopener noreferrer">OWASP Session Management Cheat Sheet</a></li>
<li><a href="https://tools.ietf.org/html/rfc6265" target="_blank" rel="noopener noreferrer">RFC 6265 - HTTP State Management Mechanism (Cookies)</a></li>
<li><a href="https://www.php.net/manual/en/function.password-hash.php" target="_blank" rel="noopener noreferrer">PHP: password_hash Documentation</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies" target="_blank" rel="noopener noreferrer">Mozilla MDN - HTTP Cookies Security</a></li>
</ul>