PHP

Dominando Sessões e Cookies: Autenticação Stateful em PHP em Projetos Reais

8 min de leitura

Dominando Sessões e Cookies: Autenticação Stateful em PHP em Projetos Reais

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 Esses parâmetros são essenciais: impede ataques XSS (Cross-Site Scripting), força HTTPS, e previne CSRF (Cross-Site Request Forgery). Nunca ignore essas configurações em produção. Autenticação com Hash de Senha Nunca armazene senhas em texto

<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">&lt;?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([

&#039;lifetime&#039; =&gt; 3600, // 1 hora

&#039;path&#039; =&gt; &#039;/&#039;,

&#039;domain&#039; =&gt; &#039;exemplo.com&#039;,

&#039;secure&#039; =&gt; true, // HTTPS apenas

&#039;httponly&#039; =&gt; true, // Sem acesso via JavaScript

&#039;samesite&#039; =&gt; &#039;Strict&#039; // Proteção contra CSRF

]);

// Verificar se o usuário está autenticado

if (!isset($_SESSION[&#039;user_id&#039;])) {

header(&#039;Location: login.php&#039;);

exit;

}

echo &quot;Bem-vindo, &quot; . htmlspecialchars($_SESSION[&#039;username&#039;]);

?&gt;</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">&lt;?php

session_start();

if ($_SERVER[&#039;REQUEST_METHOD&#039;] === &#039;POST&#039;) {

$username = $_POST[&#039;username&#039;] ?? &#039;&#039;;

$password = $_POST[&#039;password&#039;] ?? &#039;&#039;;

// Simular busca no banco de dados

$user = [

&#039;id&#039; =&gt; 1,

&#039;username&#039; =&gt; &#039;joao&#039;,

&#039;password_hash&#039; =&gt; password_hash(&#039;senha123&#039;, PASSWORD_BCRYPT)

];

if ($username === $user[&#039;username&#039;] &amp;&amp;

password_verify($password, $user[&#039;password_hash&#039;])) {

$_SESSION[&#039;user_id&#039;] = $user[&#039;id&#039;];

$_SESSION[&#039;username&#039;] = $user[&#039;username&#039;];

$_SESSION[&#039;created_at&#039;] = time();

header(&#039;Location: dashboard.php&#039;);

exit;

} else {

$error = &quot;Credenciais inválidas&quot;;

}

}

?&gt;

&lt;form method=&quot;POST&quot;&gt;

&lt;input type=&quot;text&quot; name=&quot;username&quot; required&gt;

&lt;input type=&quot;password&quot; name=&quot;password&quot; required&gt;

&lt;button type=&quot;submit&quot;&gt;Entrar&lt;/button&gt;

&lt;/form&gt;

&lt;?php if (isset($error)): ?&gt;

&lt;p&gt;&lt;?php echo htmlspecialchars($error); ?&gt;&lt;/p&gt;

&lt;?php endif; ?&gt;</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">&lt;?php

// Definir um cookie seguro

setcookie(

&#039;idioma&#039;, // nome

&#039;pt-BR&#039;, // valor

[

&#039;expires&#039; =&gt; time() + (365 24 60 * 60), // 1 ano

&#039;path&#039; =&gt; &#039;/&#039;,

&#039;secure&#039; =&gt; true,

&#039;httponly&#039; =&gt; true,

&#039;samesite&#039; =&gt; &#039;Lax&#039;

]

);

// Acessar cookie

$idioma = $_COOKIE[&#039;idioma&#039;] ?? &#039;pt-BR&#039;;

// Deletar cookie

setcookie(&#039;idioma&#039;, &#039;&#039;, [&#039;expires&#039; =&gt; time() - 3600]);

?&gt;</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">&lt;?php

session_start();

// Após validar credenciais (no login)

session_regenerate_id(true); // true = destruir sessão antiga

$_SESSION[&#039;user_id&#039;] = $user[&#039;id&#039;];

// Validar idade da sessão (logout automático)

$tempo_inatividade = 30 * 60; // 30 minutos

$tempo_atual = time();

if (isset($_SESSION[&#039;created_at&#039;])) {

if ($tempo_atual - $_SESSION[&#039;created_at&#039;] &gt; $tempo_inatividade) {

session_destroy();

header(&#039;Location: login.php?timeout=1&#039;);

exit;

}

}

// Logout

if (isset($_GET[&#039;logout&#039;])) {

session_destroy();

header(&#039;Location: index.php&#039;);

exit;

}

?&gt;</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">&lt;?php

session_start();

class SessionHandler extends SessionHandlerInterface {

private $pdo;

public function __construct(\PDO $pdo) {

$this-&gt;pdo = $pdo;

}

public function read($id) {

$stmt = $this-&gt;pdo-&gt;prepare(

&#039;SELECT data FROM sessions WHERE id = ? AND expires &gt; ?&#039;

);

$stmt-&gt;execute([$id, time()]);

$result = $stmt-&gt;fetch();

return $result ? $result[&#039;data&#039;] : &#039;&#039;;

}

public function write($id, $data) {

$stmt = $this-&gt;pdo-&gt;prepare(

&#039;INSERT INTO sessions (id, data, expires) VALUES (?, ?, ?)

ON DUPLICATE KEY UPDATE data = ?, expires = ?&#039;

);

return $stmt-&gt;execute([$id, $data, time() + 3600, $data, time() + 3600]);

}

public function destroy($id) {

return $this-&gt;pdo-&gt;prepare(&#039;DELETE FROM sessions WHERE id = ?&#039;)

-&gt;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-&gt;pdo-&gt;prepare(&#039;DELETE FROM sessions WHERE expires &lt; ?&#039;)

-&gt;execute([time()]);

}

}

// Usar o handler customizado

$handler = new SessionHandler($pdo);

session_set_save_handler($handler);

session_start();

?&gt;</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>

Comentários

Mais em PHP

Dominando Traits em PHP: Reuso de Código sem Herança em Projetos Reais
Dominando Traits em PHP: Reuso de Código sem Herança em Projetos Reais

O que são Traits e Por Que Usá-las Traits em PHP são mecanismos que permitem...

Laravel Jobs, Queues e Events na Prática na Prática
Laravel Jobs, Queues e Events na Prática na Prática

Entendendo Jobs, Queues e Events no Laravel Jobs, queues e events são pilares...

Composer: Gerenciamento de Dependências em PHP na Prática
Composer: Gerenciamento de Dependências em PHP na Prática

O que é Composer e por que você precisa dele Composer é o gerenciador de depe...