Il processo di hashing (a differenza della crittografia) produce un output dall'input dal quale non è più possibile ricavare la stringa originale.
È quindi adatto per proteggere stringhe sensibili, password e checksum.
Un'altra bella caratteristica delle funzioni di hashing è che generano sempre output della stessa lunghezza e una piccola modifica dell'input cambia sempre completamente l'intero output.
Esistono molte funzioni hash in PHP, le più importanti sono:
$password = 'password segreta';echo password_hash($password); // Bcryptecho md5($password);echo sha1($password);
Attenzione: Né
md5()
nésha1()
sono adatti per l'hashing delle password, perché è computazionalmente facile scoprire la password originale, o almeno precompilare le password. È molto meglio usarebcrypt
, che è stato sviluppato per l'hashing delle password.Il sito web md5cracker.com contiene un database di checksum (hash), provate a cercare hash:
79c2b46ce2594ecbcb5b73e928345492
, come potete vedere, quindi il puromd5()
non è così sicuro per parole e password comuni.
Bcrypt + salt
.Nell'intervento Come non sbagliare nel piano di destinazione, David Grudl ha affrontato i modi per eseguire correttamente l'hash e la memorizzazione delle password.
L'unica soluzione corretta è: Bcrypt + salt
.
In particolare:
$password = 'hash';// Genera un hash sicuroecho password_hash($password, PASSWORD_BCRYPT);// In alternativa, con una complessità maggiore (l'impostazione predefinita è 10):echo password_hash($password, PASSWORD_BCRYPT, ['costo' => 12]);
Il vantaggio di Bcryp risiede principalmente nella sua velocità e nella salatura automatica.
Il fatto che impieghi lungo per essere generato, ad esempio 100 ms, rende molto costoso per un attaccante testare molte password.
Inoltre, l'hash in uscita viene trattato automaticamente con sale casuale, il che significa che quando la stessa password viene sottoposta a hash ripetutamente, l'output è sempre un hash diverso. Pertanto, un aggressore non sarà in grado di utilizzare una tabella hash precompilata.
Pertanto, non sarà possibile verificare la correttezza della password mediante hashing ripetuto, ma sarà necessario chiamare una funzione specializzata:
if (password_verify($password, $hash)) {// La password è corretta} else {// La password non è corretta}
Per rendere più difficile il cracking dell'hash, è una buona idea inserire una stringa aggiuntiva nell'input originale. Idealmente uno a caso. Questo processo si chiama salatura delle password.
La sicurezza si basa sull'idea che un attaccante non sarà in grado di utilizzare una tabella precompilata di password e hash, perché non conoscerà il sale e dovrà decifrare le password singolarmente.
Ad esempio:
$password = 'passaporto_segreto';$salt = 'fghjgtzjhg';$hash = md5($password . $salt);echo $password; // stampa la password originaleecho $hash; // stampa l'hash della password, compreso il sale
Si potrebbe pensare che sarebbe una buona idea eseguire la funzione di hash ripetutamente, aumentando così la complessità del cracking, poiché la password originale dovrà essere sottoposta a hash ripetutamente.
Ad esempio:
$password = 'password';for ($i = 0; $i <= 1000; $i++) {$password = md5($password);}echo $password; // 1000x hash tramite md5()
Paradossalmente, la difficoltà di sfondamento si riduce o rimane pressoché invariata.
Il motivo è che la funzione md5()
è estremamente veloce e può calcolare oltre un milione di hash al secondo su un computer normale, quindi provare le password una per una non rallenta molto.
Il secondo motivo è più che altro teorico, ovvero la possibilità di incappare in una cosiddetta collisione. Se si esegue l'hash di una password ripetutamente, col tempo può accadere che si arrivi a un hash che l'aggressore conosce già e questo gli consentirà di eseguire l'hash della password utilizzando il database.
Pertanto, è meglio utilizzare una funzione di hashing lenta e sicura ed eseguire l'hashing solo una volta, trattando comunque l'output finale con il salting.
Sapevate che l'operatore === non è la scelta più sicura per il confronto degli hash nella verifica delle password?
Quando si confrontano le stringhe, le due stringhe vengono attraversate carattere per carattere finché non si raggiunge la fine (successo, sono uguali) o non si nota una differenza (le stringhe sono diverse).
E questo può essere sfruttato in un attacco. Se si misura il tempo in modo sufficientemente preciso, si può stimare quanti caratteri devono ancora essere aggiunti per ottenere una corrispondenza esatta e raggiungere la fine, oppure si può stimare la distanza percorsa dalle stringhe quando si confrontano le stringhe.
La soluzione consiste nell'utilizzare la funzione hash_equals() ovunque vengano confrontate le stringhe, e sarebbe importante se un utente malintenzionato potesse scoprire la posizione in cui il confronto è fallito.
E come fa la funzione a farlo? Si assicura che il confronto di due stringhe qualsiasi richieda sempre la stessa quantità di tempo, in modo che non si possa capire, misurando il tempo, dove si è verificata la differenza. Trovo che alcuni tipi di attacchi siano davvero molto improbabili e difficili da attuare. Questa è una di quelle.
Jan Barášek Více o autorovi
Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.
Rád vám pomůžu:
Články píše Jan Barášek © 2009-2024 | Kontakt | Mapa webu
Status | Aktualizováno: ... | it