2010-09-29 15 views
17

Uso il PHP crypt() come metodo per archiviare e verificare le password nel mio database. Uso l'hashing per altre cose, ma crypt() per le password. La documentazione non è buona e sembra che ci sia un sacco di dibattito. Sto usando blowfish e due sali per crittare una password e archiviarla nel database. Prima di memorizzare il sale e la password crittografata, (come un hash salato), ma ho realizzato la sua ridondante perché il sale fa parte della stringa di password crittografata.Sto usando correttamente la funzione crypt() di PHP?

Sono un po 'confuso su come gli attacchi di rainbow table funzionerebbero su crypt(), comunque questo aspetto è corretto dal punto di vista della sicurezza. Uso un secondo sale per aggiungere la password per aumentare l'entropia delle password brevi, probabilmente eccessivo, ma perché no?

function crypt_password($password) { 
if ($password) { 
    //find the longest valid salt allowed by server 
    $max_salt = CRYPT_SALT_LENGTH; 

    //blowfish hashing with a salt as follows: "$2a$", a two digit cost parameter, "$", and 22 base 64 
    $blowfish = '$2a$10$'; 

    //get the longest salt, could set to 22 crypt ignores extra data 
    $salt = get_salt ($max_salt); 

    //get a second salt to strengthen password 
    $salt2 = get_salt (30); //set to whatever 


    //append salt2 data to the password, and crypt using salt, results in a 60 char output 
    $crypt_pass = crypt ($password . $salt2, $blowfish . $salt); 

    //insert crypt pass along with salt2 into database. 
    $sql = "insert into database...."; 

    return true; 
    } 
} 


function get_salt($length) { 
$options = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz./'; 

$salt = ''; 

for($i = 0; $i <= $length; $i ++) { 
    $options = str_shuffle ($options); 
    $salt .= $options [rand (0, 63)]; 
} 
return $salt; 
} 

function verify_password($input_password) 
{ 
if($input_password) 
{ 
    //get stored crypt pass,and salt2 from the database 
    $stored_password = 'somethingfromdatabase'; 
    $stored_salt2 = 'somethingelsefromdatabase'; 

    //compare the crypt of input+stored_salt2 to the stored crypt password 
    if (crypt($input_password . $stored_salt2, $stored_password) == $stored_password) { 
     //authenticated 
     return true; 
    } 
    else return false; 
} 
else return false; 
} 
+0

Utilizzare 'mt_rand' invece di' rand' sarebbe un piccolo miglioramento del tuo script – Sliq

risposta

15

Si dovrebbe dare un'occhiata a PHPASS: http://www.openwall.com/phpass/ È un framework di hashing delle password che utilizza crypt() che viene utilizzato in progetti come Wordpress e phpBB.

V'è anche un ottimo articolo su questo sito circa hashing delle password, la salatura e stretching utilizzando crypt(): http://www.openwall.com/articles/PHP-Users-Passwords

UPDATE: Attualmente c'è un'alternativa per la libreria PHPASS. Nella prossima versione di PHP ci sono funzioni speciali per l'hashing e la verifica delle password (usando bcrypt): http://www.php.net/manual/en/ref.password.php. Esiste una libreria di compatibilità che implementa queste funzioni per PHP 5.3.7+: https://github.com/ircmaxell/password_compat

+1

Posso vedere come tale framework può essere utile per un approccio out of the box, ma non vedo molto diverso tra il mio codice e il codice phpass del codice. – Brian

+1

E: PHPass è un casino. Un enorme casino. È così disordinato che non ci farei affidamento. – Sliq

+0

@Panique ti piacerebbe spiegare? –

3

L'idea di un tavolo arcobaleno è che un aggressore può fare una tabella con tutte le possibili password e hash loro a casa.

E.g.

PASSWORD HASH 
iloveSO gjroewjgo 
password knbnogjwm 
secret gjroehghe 
jbieber rewgroewj 

ecc

Con questa tabella, l'attaccante in grado di convertire rapidamente qualsiasi hash a una password. La tabella Arcobaleno usa alcuni trucchi in modo che non tutti gli hash debbano essere memorizzati, ma continua comunque a calcolare tutti gli hash.

Utilizzando un sale, anche memorizzandolo con la password, lo si rende molto più difficile. Invece di eseguire l'hashing di ogni parola in un dizionario, l'utente malintenzionato dovrebbe ora cancellare hash ogni parola con ogni quantità di sale. Con un sale abbastanza lungo, questo dà abbastanza combinazioni per rendere impossibile calcolare tutti questi hash.

Quindi un salt non è pensato per essere una password aggiuntiva, nota solo per l'applicazione, è destinata a modificare la funzione di hash in modo che sia non standard.

+0

Sta usando un salt, ma è di lunghezza sconosciuta. Con un valore salino considerevolmente elevato, una tale tavola iridata sarebbe impossibile. Ad esempio 256^256, o una base256 sale di 256 byte è così grande che non abbiamo nemmeno una parola per quel numero di byte richiesto per decifrare una password di un solo carattere. – rook

2

Questo è un uso improprio di crypt() perché si sta utilizzando una primitiva deprecata. Blowfish è molto vecchio, twofish è il sostituto e anche quello è vecchio perché il trefish è quasi finalizzato. Dovresti usare un membro della famiglia sha2, sha256 o sha512 sono entrambe buone scelte. crypt() può essere usato con sha256 o sha512, dovresti usare rispettivamente i parametri CRYPT_SHA256 CRYPT_SHA512.

Anche i tuoi sali hanno un rapporto entropia/dimensioni molto piccolo, si sta utilizzando solo un set alfanumerico che è uno scherzo perché i tavoli arcobaleno alfanumerici sono i più comuni. Dovresti usare un byte completo quale base256, e ti consiglio un sale lungo 256 byte. Tieni presente che tutte le funzioni di hash sono binarie per definizione, quindi non dovresti preoccuparti di null byte e simili.

+0

Blowfish può prendere solo caratteri alfanumerici, quindi forse dovrei usare CRYPT_SHA512. – Brian

+0

@Brian Perin quindi è qualcosa di strano con crypt() perché i cifrari a blocchi sono usati per crittografare file e traffico tutto il tempo. – rook

+2

Il Blowfish usato da 'crypt()' non è esattamente lo stesso del cifrario Blowfish del vecchio: si tratta di un algoritmo di variante creato appositamente per l'hash della password/derivazione della chiave. – caf

11

L'utilizzo di crypt() è a posto. crypt($input, $stored) == $stored è il modo in cui è progettato per essere utilizzato.

La tua funzione get_salt() non è eccezionale, poiché utilizza la funzione spesso scadente rand(). Si dovrebbe prendere in considerazione l'utilizzo di una funzione casuale più forte, come openssl_random_pseudo_bytes(), invece.

0

Utilizzare SHA-512 (se disponibile) con un intervallo che include time() e openssl_random_pseudo_bytes(). Crypt è consolidato/efficiente perché restituisce il sale inserito con la stringa hash.

Problemi correlati