PHP
Funzioni di hashing della password
Ricerca…
introduzione
Poiché i servizi web più sicuri evitano di archiviare le password in formato di testo normale, le lingue come PHP offrono varie (non decodificabili) funzioni hash per supportare lo standard industriale più sicuro. Questo argomento fornisce documentazione per l'hashing corretto con PHP.
Sintassi
-
string password_hash ( string $password , integer $algo [, array $options ] )
-
boolean password_verify ( string $password , string $hash )
-
boolean password_needs_rehash ( string $hash , integer $algo [, array $options ] )
-
array password_get_info ( string $hash )
Osservazioni
Prima di PHP 5.5, è possibile utilizzare il pacchetto di compatibilità per fornire le funzioni password_*
. Si consiglia vivamente di utilizzare il pacchetto di compatibilità se si è in grado di farlo.
Con o senza il pacchetto di compatibilità, la corretta funzionalità di Bcrypt tramite crypt()
si basa su PHP 5.3.7+ altrimenti è necessario limitare le password ai set di caratteri solo ASCII.
Nota: se usi PHP 5.5 o versioni precedenti stai utilizzando una versione di PHP non supportata che non riceve più alcun aggiornamento di sicurezza. Aggiorna il prima possibile, puoi aggiornare gli hash delle password in seguito.
Selezione dell'algoritmo
Algoritmi sicuri
- bcrypt è la tua migliore opzione se usi il key stretching per aumentare il tempo di calcolo dell'hash, poiché rende gli attacchi brute force estremamente lenti .
- argon2 è un'altra opzione che sarà disponibile in PHP 7.2 .
Algoritmi insicuri
I seguenti algoritmi di hashing non sono sicuri o non sono adatti allo scopo e pertanto non dovrebbero essere utilizzati . Non sono mai stati adatti per l'hashing della password, in quanto sono progettati per diger veloci invece che per gli hash delle password con forza bruta e lenta.
Se ne usi qualcuno , incluso anche sali, dovresti passare ad uno degli algoritmi sicuri raccomandati il prima possibile .
Algoritmi considerati insicuri:
- MD4 - attacco di collisione trovato nel 1995
- MD5 - attacco di collisione trovato nel 2005
- SHA-1 : attacco di collisione dimostrato nel 2015
Alcuni algoritmi possono essere tranquillamente utilizzati come algoritmo di digest del messaggio per dimostrare l'autenticità, ma mai come algoritmo di hashing della password :
- SHA-2
- SHA-3
Nota: gli hash forti come SHA256 e SHA512 sono ininterrotti e robusti, tuttavia è generalmente più sicuro utilizzare le funzioni di hash bcrypt o argon2 poiché gli attacchi di forza bruta contro questi algoritmi sono molto più difficili per i computer classici.
Determina se un hash della password esistente può essere aggiornato ad un algoritmo più forte
Se stai utilizzando il metodo PASSWORD_DEFAULT
per consentire al sistema di scegliere l'algoritmo migliore per l'hash delle tue password, poiché l'impostazione predefinita aumenta di intensità, potresti voler ripetere le vecchie password quando gli utenti accedono
<?php
// first determine if a supplied password is valid
if (password_verify($plaintextPassword, $hashedPassword)) {
// now determine if the existing hash was created with an algorithm that is
// no longer the default
if (password_needs_rehash($hashedPassword, PASSWORD_DEFAULT)) {
// create a new hash with the new default
$newHashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT);
// and then save it to your data store
//$db->update(...);
}
}
?>
Se le funzioni password_ * non sono disponibili sul sistema (e non è possibile utilizzare il pacchetto di compatibilità collegato nelle osservazioni seguenti), è possibile determinare l'algoritmo e utilizzare per creare l'hash originale in un metodo simile al seguente:
<?php
if (substr($hashedPassword, 0, 4) == '$2y$' && strlen($hashedPassword) == 60) {
echo 'Algorithm is Bcrypt';
// the "cost" determines how strong this version of Bcrypt is
preg_match('/\$2y\$(\d+)\$/', $hashedPassword, $matches);
$cost = $matches[1];
echo 'Bcrypt cost is '.$cost;
}
?>
Creazione di un hash della password
Crea hash delle password usando password_hash()
per utilizzare l'attuale hash standard di best practice del settore o la derivazione della chiave. Al momento della stesura, lo standard è bcrypt , il che significa che PASSWORD_DEFAULT
contiene lo stesso valore di PASSWORD_BCRYPT
.
$options = [
'cost' => 12,
];
$hashedPassword = password_hash($plaintextPassword, PASSWORD_DEFAULT, $options);
Il terzo parametro non è obbligatorio .
Il valore 'cost'
dovrebbe essere scelto in base all'hardware del server di produzione. Aumentandolo si renderà la password più costosa da generare. Più è costoso generare più tempo ci vorrà chiunque cerchi di craccarlo per generarlo anche. Il costo dovrebbe idealmente essere il più alto possibile, ma in pratica dovrebbe essere impostato in modo che non rallenti troppo. Da qualche parte tra 0,1 e 0,4 secondi andrebbe bene. Usa il valore predefinito in caso di dubbio.
Su PHP inferiore a 5.5.0 le funzioni password_*
non sono disponibili. È necessario utilizzare il pacchetto di compatibilità per sostituire tali funzioni. Si noti che il pacchetto di compatibilità richiede PHP 5.3.7 o versioni successive o una versione con backport di $2y
(come ad esempio RedHat).
Se non si è in grado di utilizzarli, è possibile implementare l'hashing della password con crypt()
Poiché password_hash()
è implementata come wrapper attorno alla funzione crypt()
, non è necessario perdere alcuna funzionalità.
// this is a simple implementation of a bcrypt hash otherwise compatible
// with `password_hash()`
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
// if `CRYPT_BLOWFISH` is 1, that means bcrypt (which uses blowfish) is available
// on your system
if (CRYPT_BLOWFISH == 1) {
$salt = mcrypt_create_iv(16, MCRYPT_DEV_URANDOM);
$salt = base64_encode($salt);
// crypt uses a modified base64 variant
$source = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
$dest = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
$salt = strtr(rtrim($salt, '='), $source, $dest);
$salt = substr($salt, 0, 22);
// `crypt()` determines which hashing algorithm to use by the form of the salt string
// that is passed in
$hashedPassword = crypt($plaintextPassword, '$2y$10$'.$salt.'$');
}
Salt per l'hash della password
Nonostante l'affidabilità dell'algoritmo di crypt, esiste ancora una vulnerabilità nei confronti delle tabelle arcobaleno . Questa è la ragione, perché è consigliabile usare il sale .
Un salt è qualcosa che viene aggiunto alla password prima dell'hashing per rendere la stringa di origine univoca. Con due password identiche, gli hash risultanti saranno anche unici, poiché i loro sali sono unici.
Un sale casuale è uno dei pezzi più importanti della sicurezza della tua password. Ciò significa che anche con una tabella di ricerca di hash di password noti, un utente malintenzionato non può abbinare l'hash della password dell'utente con gli hash delle password del database poiché è stata utilizzata una sequenza casuale. Dovresti usare sempre sali casuali e crittograficamente sicuri. Leggi di più
Con l'algoritmo bcrypt
password_hash()
, il testo semplice sale viene archiviato insieme all'hash risultante, il che significa che l'hash può essere trasferito su diversi sistemi e piattaforme e deve ancora essere abbinato alla password originale.
Anche quando questo è scoraggiato, puoi usare l'opzione salt
per definire il tuo sale casuale.
$options = [
'salt' => $salt, //see example below
];
Importante Se si omette questa opzione, verrà generato un salt casuale da password_hash () per ogni hash della password. Questa è la modalità di funzionamento prevista.
L'opzione salt è stata deprecata a partire da PHP 7.0.0. Ora è preferibile utilizzare semplicemente il sale che viene generato di default.
Verifica di una password contro un hash
password_verify()
è la funzione built-in fornita (a partire da PHP 5.5) per verificare la validità di una password rispetto a un hash noto.
<?php
if (password_verify($plaintextPassword, $hashedPassword)) {
echo 'Valid Password';
}
else {
echo 'Invalid Password.';
}
?>
Tutti gli algoritmi di hashing supportati memorizzano le informazioni identificando quale hash è stato utilizzato nell'hash stesso, quindi non è necessario indicare quale algoritmo si sta utilizzando per codificare la password in chiaro con.
Se le funzioni password_ * non sono disponibili sul sistema (e non è possibile utilizzare il pacchetto di compatibilità collegato nei commenti seguenti) è possibile implementare la verifica della password con la funzione crypt()
. Si prega di notare che devono essere prese precauzioni specifiche per evitare attacchi a tempo .
<?php
// not guaranteed to maintain the same cryptographic strength of the full `password_hash()`
// implementation
if (CRYPT_BLOWFISH == 1) {
// `crypt()` discards all characters beyond the salt length, so we can pass in
// the full hashed password
$hashedCheck = crypt($plaintextPassword, $hashedPassword);
// this a basic constant-time comparison based on the full implementation used
// in `password_hash()`
$status = 0;
for ($i=0; $i<strlen($hashedCheck); $i++) {
$status |= (ord($hashedCheck[$i]) ^ ord($hashedPassword[$i]));
}
if ($status === 0) {
echo 'Valid Password';
}
else {
echo 'Invalid Password';
}
}
?>