Ok, ci sono due problemi separati ma correlati, e ognuno è gestito in modo diverso.
Sessione fissa
È qui che un utente malintenzionato imposta esplicitamente l'identificatore di sessione di una sessione per un utente. In genere in PHP è fatto dando loro un URL come http://www.example.com/index...?session_name=sessionid
. Una volta che l'attaccante fornisce l'URL al client, l'attacco è lo stesso di un attacco di dirottamento di sessione.
Esistono alcuni modi per impedire la fissazione della sessione (esegui tutte):
Imposta session.use_trans_sid = 0
nel tuo php.ini
file. Questo dirà a PHP di non includere l'identificatore nell'URL e di non leggere l'URL per gli identificatori.
Imposta session.use_only_cookies = 1
nel tuo php.ini
file. Questo dirà a PHP di non usare mai gli URL con identificatori di sessione.
Rigenerare l'ID sessione ogni volta che lo stato della sessione cambia. Ciò significa che uno dei seguenti:
- Autenticazione utente
- Memorizzazione di informazioni sensibili nella sessione
- Cambiare qualcosa sulla sessione
- eccetera...
Dirottamento della sessione
Qui è dove un utente malintenzionato ottiene un identificativo di sessione ed è in grado di inviare richieste come se fossero quell'utente. Ciò significa che, poiché l'attaccante ha l'identificatore, sono quasi indistinguibili dall'utente valido rispetto al server.
Non è possibile impedire direttamente il dirottamento della sessione. Puoi comunque fare dei passi per renderlo molto difficile e difficile da usare.
Usa un identificatore hash di sessione forte: session.hash_function
in php.ini
. Se PHP <5.3, session.hash_function = 1
impostalo su per SHA1. Se PHP> = 5.3, impostalo su session.hash_function = sha256
o session.hash_function = sha512
.
Invia un hash forte: session.hash_bits_per_character
in php.ini
. Impostalo su session.hash_bits_per_character = 5
. Sebbene ciò non renda più difficile decifrare, fa la differenza quando l'attaccante tenta di indovinare l'identificatore di sessione. L'ID sarà più breve, ma utilizza più caratteri.
Imposta un'entropia aggiuntiva con session.entropy_file
e session.entropy_length
nel tuo php.ini
file. Impostare il primo su session.entropy_file = /dev/urandom
e il secondo sul numero di byte che verranno letti dal file entropy, ad esempio session.entropy_length = 256
.
Cambia il nome della sessione dal PHPSESSID predefinito. Ciò si ottiene chiamando session_name()
con il proprio nome identificativo come primo parametro prima di chiamare session_start
.
Se sei davvero paranoico, puoi anche ruotare il nome della sessione, ma fai attenzione che tutte le sessioni verranno automaticamente invalidate se lo cambi (ad esempio, se lo rendi dipendente dal tempo). Ma a seconda del tuo caso d'uso, potrebbe essere un'opzione ...
Ruota spesso l'identificatore di sessione. Non farei ogni richiesta (a meno che tu non abbia davvero bisogno di quel livello di sicurezza), ma a intervalli casuali. Vuoi cambiarlo spesso poiché se un attaccante dirotta una sessione non vuoi che siano in grado di usarlo per troppo tempo.
Includi l' agente utente$_SERVER['HTTP_USER_AGENT']
nella sessione. Fondamentalmente, quando inizia la sessione, archiviarlo in qualcosa di simile $_SESSION['user_agent']
. Quindi, ad ogni richiesta successiva, verificare che corrisponda. Nota che questo può essere simulato, quindi non è affidabile al 100%, ma è meglio di così.
Includi l' indirizzo IP dell'utente$_SERVER['REMOTE_ADDR']
nella sessione. Fondamentalmente, quando inizia la sessione, archiviarlo in qualcosa di simile $_SESSION['remote_ip']
. Questo può essere problematico da alcuni ISP che usano più indirizzi IP per i loro utenti (come faceva AOL). Ma se lo usi, sarà molto più sicuro. L'unico modo per un utente malintenzionato di falsificare l'indirizzo IP è compromettere la rete a un certo punto tra l'utente reale e l'utente. E se compromettono la rete, possono fare molto peggio di un dirottamento (come attacchi MITM, ecc.).
Includere un token nella sessione e sul lato browser che si incrementa e si confronta spesso. Fondamentalmente, per ogni richiesta fare $_SESSION['counter']++
sul lato server. Fai anche qualcosa in JS sul lato browser per fare lo stesso (usando una memoria locale). Quindi, quando si invia una richiesta, è sufficiente prendere un nonce di un token e verificare che il nonce sia lo stesso sul server. In questo modo, dovresti essere in grado di rilevare una sessione dirottata poiché l'attaccante non avrà il contatore esatto, o se lo fanno avrai 2 sistemi che trasmettono lo stesso conteggio e possono dire che uno è forgiato. Questo non funzionerà per tutte le applicazioni, ma è un modo per combattere il problema.
Una nota sui due
La differenza tra Session Fixation e Hijacking sta solo nel modo in cui l'identificatore di sessione è compromesso. Nella fissazione, l'identificatore è impostato su un valore che l'attaccante conosce prima. Nel dirottamento viene indovinato o rubato all'utente. Altrimenti gli effetti dei due sono gli stessi una volta che l'identificatore è stato compromesso.
Rigenerazione ID sessione
Ogni volta che si rigenera l'identificatore di sessione utilizzando session_regenerate_id
la vecchia sessione, è necessario eliminarlo. Ciò accade in modo trasparente con il gestore della sessione principale. Tuttavia, alcuni gestori di sessioni personalizzati che utilizzanosession_set_save_handler()
non lo fanno e sono aperti agli attacchi con identificatori di sessione precedenti. Assicurati che se stai usando un gestore di sessioni personalizzato, tieni traccia dell'identificatore che apri e se non è lo stesso che salvi che elimini esplicitamente (o cambi) l'identificatore su quello vecchio.
Usando il gestore di sessioni predefinito, stai bene solo chiamando session_regenerate_id(true)
. Ciò rimuoverà le informazioni sulla vecchia sessione per te. Il vecchio ID non è più valido e causerà la creazione di una nuova sessione se l'attaccante (o chiunque altro) tenti di utilizzarlo. Fai attenzione con i gestori di sessione personalizzati ...
Distruggere una sessione
Se hai intenzione di distruggere una sessione (ad esempio quando esci), assicurati di distruggerla completamente. Ciò include la disattivazione del cookie. Utilizzando session_destroy
:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}