Sessioni e autenticazione in PHP: ricordare il login con “Remember Me” in modo sicuro

by theArchitect
SHARE
Sessioni e autenticazione in PHP: ricordare il login con “Remember Me” in modo sicuro
© Guida-HTML5.it

Introduzione

Quando un utente accede a un sito, spesso vuole evitare di inserire la password a ogni visita. La classica funzionalità “Ricordami” (o Remember Me) risponde proprio a questa esigenza: mantiene l’utente autenticato anche dopo la chiusura del browser, senza affidarsi alla sola sessione PHP tradizionale.

Questo sotto-argomento è molto utile perché unisce sessioni, cookie e autenticazione persistente in un flusso realistico. È anche un punto delicato dal punto di vista della sicurezza: implementarlo male può esporre l’applicazione a furto di credenziali o accessi non autorizzati. In questo tutorial vedremo un approccio pratico e più sicuro, basato su token casuali salvati lato server e associati a un cookie sul client.

L’idea è semplice:

  • l’utente effettua il login con email e password;
  • se seleziona “ricordami”, generiamo un token casuale;
  • salviamo nel database solo l’hash del token, non il token in chiaro;
  • inviamo al browser un cookie con il token completo;
  • alle visite successive, se la sessione non esiste, controlliamo il cookie e ricreiamo la sessione.

Questo approccio è più robusto rispetto a salvare semplicemente l’ID utente nel cookie, perché il token può essere revocato, ruotato e verificato in modo sicuro.

Codice completo

Di seguito trovi un esempio completo e commentato. Per semplicità useremo PDO e una tabella dedicata ai token di remember me.

<?php
declare(strict_types=1);

session_start();

/**
 * Connessione PDO
 * In un progetto reale sposta questi dati in un file di configurazione sicuro.
 */
$pdo = new PDO(
    ´mysql:host=localhost;dbname=app;charset=utf8mb4´,
    ´root´,
    ´´,
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    ]
);

/**
 * Configurazione cookie "remember me"
 */
const REMEMBER_COOKIE_NAME = ´remember_me´;
const REMEMBER_COOKIE_LIFETIME = 60 * 60 * 24 * 30; // 30 giorni

/**
 * Funzione di supporto per impostare un cookie sicuro.
 */
function setSecureCookie(string $name, string $value, int $lifetime): void
{
    setcookie($name, $value, [
        ´expires´  => time() + $lifetime,
        ´path´     => ´/´,
        ´secure´   => true,   // richiede HTTPS
        ´httponly´ => true,   // non leggibile da JavaScript
        ´samesite´ => ´Lax´,
    ]);
}

/**
 * Genera un token casuale sicuro.
 */
function generateRememberToken(): string
{
    return bin2hex(random_bytes(32));
}

/**
 * Salva il token in forma hashata nel database.
 * Il cookie conterrà il token in chiaro, ma nel DB teniamo solo l´hash.
 */
function storeRememberToken(PDO $pdo, int $userId, string $token): void
{
    $tokenHash = hash(´sha256´, $token);
    $expiresAt = (new DateTimeImmutable(´+30 days´))-

Per funzionare correttamente, serve anche una tabella database per i token persistenti.

CREATE TABLE remember_tokens (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    token_hash CHAR(64) NOT NULL,
    expires_at DATETIME NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_user_token (user_id, token_hash),
    INDEX idx_expires_at (expires_at)
);

Spiegazione

Il punto chiave di questa soluzione è distinguere tra sessione e persistenza. La sessione PHP è temporanea: vive sul server e si appoggia a un cookie di sessione nel browser. Quando il browser si chiude o la sessione scade, l’utente perde l’accesso. Il cookie “remember me”, invece, serve a riconoscere l’utente in un secondo momento e a creare una nuova sessione.

Flusso di login

  • L’utente invia email e password.
  • Con password_verify() confrontiamo la password con l’hash salvato nel database.
  • Se le credenziali sono corrette, creiamo la sessione con session_regenerate_id(true) per ridurre il rischio di session fixation.
  • Se l’utente ha selezionato “ricordami”, generiamo un token casuale e lo salviamo in hash nel database.
  • Nel cookie memorizziamo una coppia userId:token.

Perché hashare il token

Se un attaccante riuscisse a leggere il database, non dovrebbe trovare token utilizzabili in chiaro. Salvare solo l’hash rende il furto molto meno utile. Quando l’utente torna sul sito, il server ricalcola l’hash del token contenuto nel cookie e verifica se corrisponde a un record valido.

Autenticazione automatica

La funzione authenticateFromRememberCookie() controlla se esiste il cookie, lo separa in ID utente e token, calcola l’hash e cerca una corrispondenza nel database. Se il token è valido e non scaduto, viene ricreata la sessione. In questo modo il browser non “rimane loggato” direttamente: è il server che ricostruisce l’identità dell’utente in modo controllato.

Logout completo

Un buon logout non deve limitarsi a distruggere la sessione. Deve anche revocare il token persistente, altrimenti il cookie remember me potrebbe continuare a funzionare anche dopo la disconnessione. Per questo la funzione logout() elimina il token dal database e cancella il cookie dal browser.

Best practice

  • Usa sempre HTTPS: il cookie remember me deve viaggiare solo su connessioni cifrate.
  • Imposta Secure, HttpOnly e SameSite: riducono il rischio di furto e uso improprio del cookie.
  • Non salvare mai password o dati sensibili nel cookie: solo token casuali.
  • Salva nel database solo l’hash del token: se il DB viene compromesso, il token non è immediatamente riutilizzabile.
  • Ruota i token: dopo un login automatico, puoi generare un nuovo token e invalidare il precedente per aumentare la sicurezza.
  • Imposta una scadenza reale: 15, 30 o 60 giorni, a seconda del contesto applicativo.
  • Revoca tutti i token al cambio password: se l’utente cambia password, è prudente invalidare i remember token attivi.
  • Proteggi il form di login con CSRF token se l’applicazione lo richiede.

Errore comune da evitare

Una cattiva implementazione consiste nel salvare nel cookie un semplice valore come user_id=12 e considerarlo sufficiente per autenticare l’utente. Questo è insicuro perché chiunque possa modificare il cookie potrebbe impersonare altri utenti. Il token casuale, invece, deve essere imprevedibile e verificato lato server.

Riepilogo

La funzionalità “Ricordami” è molto comoda, ma va progettata con attenzione. In questo tutorial abbiamo visto come combinare sessioni PHP e autenticazione persistente usando un token sicuro, un cookie protetto e una tabella dedicata nel database. L’obiettivo non è sostituire la sessione, ma creare un meccanismo affidabile per ricostruirla quando l’utente torna sul sito.

Se vuoi ricordare un utente in modo sicuro, segui questa logica:

  • autentica normalmente con email e password;
  • crea la sessione;
  • se richiesto, genera un token casuale;
  • salva solo l’hash del token nel database;
  • memorizza il token nel cookie con protezioni adeguate;
  • verifica il cookie solo se la sessione non è già presente;
  • revoca il token al logout o in caso di eventi critici.

Questa è una base solida per costruire sistemi di autenticazione più moderni, usabili e sicuri.

Approfondisci con risorse ufficiali

  • PHP Manual - Sessions: documentazione ufficiale sulle sessioni PHP.
  • PHP Manual - setcookie(): guida completa alla gestione dei cookie.
  • PHP Manual - password_hash() e password_verify(): funzioni consigliate per la gestione sicura delle password.
  • OWASP Authentication Cheat Sheet: best practice di sicurezza per l’autenticazione.
  • OWASP Session Management Cheat Sheet: linee guida per la gestione sicura delle sessioni.

SHARE