it-swarm-eu.dev

Sicuro hash e sale per PHP Le password

Attualmente è stato detto che MD5 è parzialmente pericoloso. Prendendo questo in considerazione, mi piacerebbe sapere quale meccanismo utilizzare per la protezione con password.

Questa domanda, Il "doppio hashing" è una password meno sicura di una semplice operazione di hashing? suggerisce che l'hashing di più volte può essere una buona idea, considerando che Come implementare la protezione con password per i singoli file? suggerisce di usare il sale.

Sto usando PHP. Voglio un sistema sicuro e veloce di crittografia della password. Macinare una password un milione di volte può essere più sicuro, ma anche più lento. Come raggiungere un buon equilibrio tra velocità e sicurezza? Inoltre, preferirei che il risultato avesse un numero costante di caratteri.

  1. Il meccanismo di hashing deve essere disponibile in PHP
  2. Deve essere al sicuro
  3. Può usare il sale (in questo caso, tutti i sali sono ugualmente buoni? C'è un modo per generare dei buoni sali?)

Inoltre, dovrei memorizzare due campi nel database (uno usa MD5 e un altro usando SHA, per esempio)? Lo renderebbe più sicuro o meno sicuro?

Nel caso in cui non fossi abbastanza chiaro, voglio sapere quali funzioni di hashing usare e come scegliere un buon sale per avere un meccanismo di protezione della password sicuro e veloce.

Domande correlate che non coprono la mia domanda:

Qual è la differenza tra SHA e MD5 in PHP
Crittografia semplice password
Metodi sicuri di memorizzazione delle chiavi, password per asp.net
Come implementeresti le password salate in Tomcat 5.5

1115
luiscubal

Una risposta molto più breve e più sicura - non scrivere il proprio meccanismo password , usa un meccanismo provato e testato.

  • PHP 5.5 o successivo: password_hash () è di buona qualità e parte del PHP core.
  • Le versioni precedenti di PHP: OpenWall's phpass library è molto meglio della maggior parte del codice personalizzato - utilizzato in WordPress, Drupal, ecc.

La maggior parte dei programmatori semplicemente non ha le competenze per scrivere codice relativo alla crittografia senza introdurre vulnerabilità.

Autotest rapido: cos'è lo stretching della password e quante iterazioni dovresti usare? Se non conosci la risposta, dovresti usare password_hash(), poiché l'estensione della password è ora una caratteristica fondamentale dei meccanismi delle password dovuta a CPU molto più veloci e all'uso di GPU e FPGA per decifrare le password a un tasso di miliardi di ipotesi al secondo (con GPU).

Ad esempio, è possibile decifrare tutte le password di Windows di 8 caratteri in 6 ore utilizzando 25 GPU installate in 5 PC desktop. Questo è bruto-forzare cioè enumerare e controllare ogni password Windows di 8 caratteri, compresi i caratteri speciali, e non è un attacco di dizionario. Era il 2012, dal 2018 potresti usare meno GPU, o crackare più velocemente con 25 GPU.

Ci sono anche molti attacchi Rainbow table su password di Windows che girano su CPU ordinarie e sono molto veloci. Tutto questo perché Windows ancoranon sale o non allunga le sue password, anche in Windows 10 - non commettono lo stesso errore di Microsoft!

Vedi anche:

  • ottima risposta con più sul perché password_hash() o phpass sono il modo migliore per andare.
  • buon articolo del blog che fornisce 'fattori di lavoro' raccomandati (numero di iterazioni) per i principali algoritmi inclusi bcrypt, scrypt e PBKDF2.
128
RichVel

Non memorizzerei l'hash della password in due modi diversi, perché il sistema è debole almeno quanto il più debole degli algoritmi di hash in uso.

41
Tom Haigh

A partire da PHP 5.5, PHP ha funzioni semplici e sicure per l'hashing e la verifica delle password, password_hash () e password_verify ()

$password = 'anna';
$hash = password_hash($password, PASSWORD_DEFAULT);
$expensiveHash = password_hash($password, PASSWORD_DEFAULT, array('cost' => 20));

password_verify('anna', $hash); //Returns true
password_verify('anna', $expensiveHash); //Also returns true
password_verify('elsa', $hash); //Returns false

Quando si usa password_hash(), genera un salt casuale e lo include nell'hash outout (insieme al costo e all'algoritmo usato). password_verify() legge quindi l'hash e determina il metodo salt e di crittografia usato e lo verifica contro la password in chiaro fornita .

Fornendo PASSWORD_DEFAULT istruisce PHP per utilizzare l'algoritmo di hashing predefinito della versione installata di PHP. Esattamente quale algoritmo significa che è destinato a cambiare nel tempo nelle versioni future, in modo che sia sempre uno degli algoritmi disponibili più forti.

L'aumento dei costi (che ha un valore predefinito di 10) rende l'hash più difficile da applicare alla forza bruta, ma significa anche generare hash e verificare le password contro di loro sarà più utile per la CPU del tuo server.

Si noti che anche se l'algoritmo di hashing predefinito può cambiare, gli hash precedenti continueranno a essere verificati correttamente poiché l'algoritmo utilizzato è archiviato nell'hash e password_verify() lo preleva.

34

Anche se la domanda è stata risolta, voglio solo ribadire che i sali usati per l'hashing dovrebbero essere casuali e non come l'indirizzo di posta elettronica come suggerito nella prima risposta.

Ulteriori spiegazioni sono disponibili su- http://www.pivotalsecurity.com/blog/password-hashing-salt-should-it-be-random/

Recentemente ho avuto una discussione se gli hash delle password salati con bit casuali sono più sicuri di quelli salati con sali ipotetici o conosciuti. Vediamo: Se il sistema che memorizza la password è compromesso e il sistema che memorizza il sale casuale, l'attaccante avrà accesso all'hash e al sale, quindi se il sale è casuale o meno, non importa. L'attaccante può generare tavoli Rainbow pre-calcolati per rompere l'hash. Ecco la parte interessante: non è così banale generare tabelle pre-calcolate. Prendiamo un esempio di WPA modello di sicurezza. La password WPA non viene mai inviata al punto di accesso wireless. Invece, è sottoposto a hash con il tuo SSID (il nome della rete, come Linksys, Dlink, ecc.). Una buona spiegazione di come funziona è qui. Per recuperare la password dall'hash, è necessario conoscere la password e anche salt (nome della rete). Church of Wifi ha già tabelle di hash pre-calcolate con top 1000 SSID e circa 1 milione di password. La dimensione è di tutte le tabelle è di circa 40 GB. Come puoi leggere sul loro sito, qualcuno ha utilizzato 15 array FGPA per 3 giorni per generare queste tabelle. Supponendo che la vittima stia usando il SSID come "a387csf3" e la password come "123456", sarà incrinata da quei tavoli? No! .. non può. Anche se la password è debole, le tabelle non hanno hash per SSID a387csf3. Questa è la bellezza di avere sale casuale. Distaccerà i cracker che prosperano su tavoli precompilati. Può fermare un hacker determinato? Probabilmente no. Ma l'uso di sali casuali fornisce ulteriore livello di difesa. Mentre siamo su questo argomento, discutiamo il vantaggio aggiuntivo di immagazzinare sali casuali su un sistema separato. Scenario n. 1: Gli hash delle password sono memorizzati sul sistema X e i valori saltati per l'hashing sono memorizzati sul sistema Y. Questi valori salt sono ipotizzabili o noti (ad es. Nome utente) Scenario n. 2: Gli hash delle password sono memorizzati sul sistema X e i valori di sale usati per l'hashing è memorizzato sul sistema Y. Questi valori di sale sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi intuire, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (scenario n. 2). L'attaccante dovrà indovinare i valori di aggiunta per essere in grado di rompere gli hash. Se si utilizza un sale a 32 bit, sarà possibile richiedere 2 ^ 32 = 4.294.967.296 (circa 4.2 miliardi) di iterazioni per ogni password indovinata.

31
Gaurav Kumar

Voglio solo sottolineare che PHP 5.5 include un API hashing password che fornisce un wrapper attorno a crypt(). Questa API semplifica in modo significativo l'attività di hashing, verifica e rehashing degli hash delle password. L'autore ha anche rilasciato un pacchetto di compatibilità (sotto forma di un singolo file password.php che è semplicemente require da usare), per quelli che usano PHP 5.3.7 e successivi e vogliono usare questo adesso.

Supporta solo BCRYPT per ora, ma mira ad essere facilmente esteso per includere altre tecniche di hashing della password e poiché la tecnica e il costo sono memorizzati come parte dell'hash, le modifiche alla tecnica di hashing/costo non annulleranno gli hash correnti, il framework automaticamente, utilizzare la tecnica/il costo corretto durante la convalida. Gestisce anche la generazione di un sale "sicuro" se non si definisce esplicitamente il proprio.

L'API espone quattro funzioni:

  • password_get_info(): restituisce informazioni sull'hash specificato
  • password_hash(): crea un hash della password
  • password_needs_rehash() - controlla se l'hash dato corrisponde alle opzioni date. Utile per verificare se l'hash è conforme al tuo schema di tecnica/costo attuale che ti consente di ripetere se necessario
  • password_verify() - verifica che una password corrisponda a un hash

Al momento queste funzioni accettano le costanti password PASSWORD_BCRYPT e PASSWORD_DEFAULT, che al momento sono sinonimi, con la differenza che PASSWORD_DEFAULT "potrebbe cambiare nelle versioni più recenti PHP quando sono supportati algoritmi di hashing più recenti e più potenti." L'uso di PASSWORD_DEFAULT e password_needs_rehash () all'accesso (e il rehashing se necessario) dovrebbe garantire che gli hash siano ragionevolmente resilienti agli attacchi di forza bruta con poco o nessun lavoro per te.

EDIT: Ho appena capito che questo è citato brevemente nella risposta di Robert K. Lascerò questa risposta qui poiché penso che fornisca un po 'più di informazioni su come funziona e sulla facilità d'uso che fornisce a coloro che non conoscono la sicurezza.

26
JonoCoetzee

Sto usando Phpass che è una semplice classe PHP con un solo file che potrebbe essere implementata molto facilmente in quasi ogni progetto PHP. Vedi anche L'H .

Per impostazione predefinita utilizzava la crittografia più potente disponibile implementata in Phpass, che è bcrypt e ricade in altre crittografie fino a MD5 per fornire compatibilità con le versioni precedenti di framework come Wordpress.

L'hash restituito potrebbe essere memorizzato nel database così com'è. L'esempio di utilizzo per la generazione di hash è:

$t_hasher = new PasswordHash(8, FALSE);
$hash = $t_hasher->HashPassword($password);

Per verificare la password, si può usare:

$t_hasher = new PasswordHash(8, FALSE);
$check = $t_hasher->CheckPassword($password, $hash);
18
rabudde

COSE DA RICORDARE

Molto è stato detto sulla crittografia della password per PHP, la maggior parte dei quali è un ottimo consiglio, ma prima ancora di iniziare il processo di utilizzo di PHP per la crittografia della password assicurati di avere implementato o pronto per l'implementazione .

SERVER

PORTS

Non importa quanto sia buona la tua crittografia se non proteggi adeguatamente il server che esegue PHP e DB tutti i tuoi sforzi sono inutili. La maggior parte dei server funziona in modo simile, hanno porte assegnate per permetterti di accedervi da remoto tramite ftp o Shell. Assicurati di cambiare la porta predefinita di cui hai mai attivato la connessione remota. Non facendolo, in effetti hai fatto in modo che l'attaccante faccia un passo in meno nell'accedere al tuo sistema.

USERNAME

Per tutto ciò che è buono al mondo non utilizzare il nome utente admin, root o qualcosa di simile. Inoltre, se si è su un sistema basato su UNIX NON rendere accessibile l'accesso all'account root, dovrebbe sempre essere solo Sudo.

PAROLA D'ORDINE

Dì ai tuoi utenti di creare password valide per evitare di essere violati, di fare lo stesso. Qual è il punto in cui passa tutto lo sforzo di bloccare la porta principale quando hai la backdoor spalancata.

DATABASE

SERVER

Idealmente si desidera il DB e l'APPLICAZIONE su server separati. Questo non è sempre possibile a causa dei costi, ma consente una certa sicurezza in quanto l'attaccante dovrà passare attraverso due passaggi per accedere completamente al sistema.

UTENTE

Fai in modo che l'applicazione disponga di un proprio account per accedere al DB e fornisca solo i privilegi necessari.

Quindi avere un account utente separato per te che non è memorizzato da nessuna parte sul server, nemmeno nell'applicazione.

Come sempre NON fare questa radice o qualcosa di simile.

PAROLA D'ORDINE

Seguire le stesse linee guida di tutte le password valide. Inoltre, non riutilizzare la stessa password su qualsiasi account SERVER o DB sullo stesso sistema.

PHP

PAROLA D'ORDINE

MAI MAI memorizzare una password nel DB, invece memorizzare l'hash e il sale unico, spiegherò perché dopo.

HASHING

ONE WAY HASHING !!!!!!!, Mai hash una password in modo che possa essere invertita, Hash dovrebbe essere unidirezionale, nel senso che non li si inverte e li si confronta con la password, invece si hash la password inserita allo stesso modo e confrontare i due hash. Ciò significa che anche se un utente malintenzionato accede al DB, non sa quale sia la vera password, ma solo il suo hash risultante. Ciò significa più sicurezza per i tuoi utenti nel peggiore scenario possibile.

Esistono molte buone funzioni di hashing (password_hash, hash, etc ...) ma è necessario selezionare un buon algoritmo affinché l'hash sia efficace. (bcrypt e quelli simili ad esso sono algoritmi decenti).

Quando la velocità di hashing è la chiave, tanto più lento è il più resistente agli attacchi di forza bruta.

Uno degli errori più comuni nell'hashing è che gli hash non sono unici per gli utenti. Ciò è principalmente dovuto al fatto che i sali non sono generati in modo univoco.

SALTING

Le password devono essere sempre salate prima dell'hash. Salting aggiunge una stringa casuale alla password in modo che password simili non appaiano uguali nel DB. Tuttavia se il sale non è univoco per ogni utente (ad esempio: si utilizza un sale codificato duro) di quanto tu abbia praticamente reso il tuo sale senza valore. Perché una volta che un utente malintenzionato calcola una password, ha il sale per tutti loro.

Quando crei un sale, assicurati che sia univoco per la password che sta salendo, quindi memorizza sia l'hash completato che il sale nel tuo DB. Ciò che questo farà è fare in modo che un attaccante debba crackare singolarmente ogni sale e hash prima che possano ottenere l'accesso. Questo significa molto più lavoro e tempo per l'attaccante.

UTENTI CHE CREANO PASSWORD

Se l'utente sta creando una password attraverso il frontend significa che deve essere inviata al server. Questo apre un problema di sicurezza perché ciò significa che la password non crittografata viene inviata al server e se un utente malintenzionato è in grado di ascoltare e accedere a tutti gli elementi di sicurezza in PHP non ha alcun valore. SEMPRE trasmettono i dati in modo SICURO, questo viene fatto tramite SSL, ma sii stanco anche se SSL non è perfetto (il difetto di Heartbleed di OpenSSL ne è un esempio).

Inoltre, fai in modo che l'utente crei una password sicura, è semplice e dovrebbe sempre essere fatto, l'utente sarà grato per questo alla fine.

Infine, a prescindere dalle misure di sicurezza adottate, nulla è sicuro al 100%, più avanzata è la tecnologia da proteggere, più gli attacchi diventeranno avanzati. Ma seguire questi passaggi renderà il tuo sito più sicuro e molto meno desiderabile da attaccare.

Ecco una classe PHP che crea un hash e sale facilmente per una password

http://git.io/mSJqpw

13
wmfrancia

Google dice che SHA256 è disponibile per PHP.

Dovresti assolutamente usare un sale. Ti consiglio di utilizzare byte casuali (e non limitarti a caratteri e numeri). Come sempre, più a lungo si sceglie, più sicuro, più lento diventa. 64 byte dovrebbero andare bene, credo.

12
AticusFinch

Ho trovato l'argomento perfetto su questo argomento qui: https://crackstation.net/hashing-security.htm , volevo che tu ne traessi beneficio, qui c'è anche il codice sorgente che ha fornito prevenzione contro attacchi basati sul tempo .

<?php
/*
 * Password hashing with PBKDF2.
 * Author: havoc AT defuse.ca
 * www: https://defuse.ca/php-pbkdf2.htm
 */

// These constants may be changed without breaking existing hashes.
define("PBKDF2_HASH_ALGORITHM", "sha256");
define("PBKDF2_ITERATIONS", 1000);
define("PBKDF2_SALT_BYTES", 24);
define("PBKDF2_HASH_BYTES", 24);

define("HASH_SECTIONS", 4);
define("HASH_ALGORITHM_INDEX", 0);
define("HASH_ITERATION_INDEX", 1);
define("HASH_SALT_INDEX", 2);
define("HASH_PBKDF2_INDEX", 3);

function create_hash($password)
{
    // format: algorithm:iterations:salt:hash
    $salt = base64_encode(mcrypt_create_iv(PBKDF2_SALT_BYTES, MCRYPT_DEV_URANDOM));
    return PBKDF2_HASH_ALGORITHM . ":" . PBKDF2_ITERATIONS . ":" .  $salt . ":" . 
        base64_encode(pbkdf2(
            PBKDF2_HASH_ALGORITHM,
            $password,
            $salt,
            PBKDF2_ITERATIONS,
            PBKDF2_HASH_BYTES,
            true
        ));
}

function validate_password($password, $good_hash)
{
    $params = explode(":", $good_hash);
    if(count($params) < HASH_SECTIONS)
       return false; 
    $pbkdf2 = base64_decode($params[HASH_PBKDF2_INDEX]);
    return slow_equals(
        $pbkdf2,
        pbkdf2(
            $params[HASH_ALGORITHM_INDEX],
            $password,
            $params[HASH_SALT_INDEX],
            (int)$params[HASH_ITERATION_INDEX],
            strlen($pbkdf2),
            true
        )
    );
}

// Compares two strings $a and $b in length-constant time.
function slow_equals($a, $b)
{
    $diff = strlen($a) ^ strlen($b);
    for($i = 0; $i < strlen($a) && $i < strlen($b); $i++)
    {
        $diff |= ord($a[$i]) ^ ord($b[$i]);
    }
    return $diff === 0; 
}

/*
 * PBKDF2 key derivation function as defined by RSA's PKCS #5: https://www.ietf.org/rfc/rfc2898.txt
 * $algorithm - The hash algorithm to use. Recommended: SHA256
 * $password - The password.
 * $salt - A salt that is unique to the password.
 * $count - Iteration count. Higher is better, but slower. Recommended: At least 1000.
 * $key_length - The length of the derived key in bytes.
 * $raw_output - If true, the key is returned in raw binary format. Hex encoded otherwise.
 * Returns: A $key_length-byte key derived from the password and salt.
 *
 * Test vectors can be found here: https://www.ietf.org/rfc/rfc6070.txt
 *
 * This implementation of PBKDF2 was originally created by https://defuse.ca
 * With improvements by http://www.variations-of-shadow.com
 */
function pbkdf2($algorithm, $password, $salt, $count, $key_length, $raw_output = false)
{
    $algorithm = strtolower($algorithm);
    if(!in_array($algorithm, hash_algos(), true))
        die('PBKDF2 ERROR: Invalid hash algorithm.');
    if($count <= 0 || $key_length <= 0)
        die('PBKDF2 ERROR: Invalid parameters.');

    $hash_length = strlen(hash($algorithm, "", true));
    $block_count = ceil($key_length / $hash_length);

    $output = "";
    for($i = 1; $i <= $block_count; $i++) {
        // $i encoded as 4 bytes, big endian.
        $last = $salt . pack("N", $i);
        // first iteration
        $last = $xorsum = hash_hmac($algorithm, $last, $password, true);
        // perform the other $count - 1 iterations
        for ($j = 1; $j < $count; $j++) {
            $xorsum ^= ($last = hash_hmac($algorithm, $last, $password, true));
        }
        $output .= $xorsum;
    }

    if($raw_output)
        return substr($output, 0, $key_length);
    else
        return bin2hex(substr($output, 0, $key_length));
}
?>
8
Jason OOO

Alla fine, il doppio hashing, matematicamente, non fornisce alcun vantaggio. In pratica, tuttavia, è utile per prevenire attacchi basati su tabelle Rainbow. In altre parole, non è più vantaggioso dell'hashing con un salt, che richiede molto meno tempo del processore nell'applicazione o sul server.

7
Max

Di solito uso SHA1 e sale con l'ID utente (o qualche altra informazione utente specifica), e a volte uso anche un sale costante (quindi ho 2 parti per il sale).

SHA1 è ora considerato anche un po 'compromesso, ma in misura molto minore rispetto a MD5. Usando un sale (qualsiasi sale), stai impedendo l'uso di un generico Rainbow table per attaccare i tuoi hash (alcune persone hanno persino avuto successo usando Google come una sorta di tavolo Rainbow cercando l'hash). Un utente malintenzionato potrebbe in teoria generare una tabella Arcobaleno usando il tuo sale, ecco perché è necessario includere un sale specifico per utente. In questo modo, dovranno generare una tabella Rainbow per ogni record del tuo sistema, non solo uno per l'intero sistema! Con questo tipo di salatura, anche MD5 è decentemente sicuro.

6
rmeador

SHA1 e un sale dovrebbe essere sufficiente (dipende, naturalmente, dal fatto che stiate codificando qualcosa per Fort Knox o un sistema di login per la vostra lista della spesa) per il prossimo futuro. Se SHA1 non è abbastanza buono per te, usa SHA256 .

L'idea di un sale è di sbilanciare i risultati dell'asportazione, per così dire. Ad esempio, è noto che l'hash MD5 di una stringa vuota è d41d8cd98f00b204e9800998ecf8427e. Quindi, se qualcuno con una memoria abbastanza buona vedrebbe quell'hash e sa che è l'hash di una stringa vuota. Ma se la stringa è salata (ad esempio, con la stringa "MY_PERSONAL_SALT"), l'hash per la 'stringa vuota' (cioè "MY_PERSONAL_SALT") diventa aeac2612626724592271634fb14d3ea6, quindi non ovvio per il backtrace. Quello che sto cercando di dire è che è meglio usare any salt, piuttosto che non farlo. Pertanto, non è troppo importante sapere quale sale da usare.

Ci sono in realtà siti web che fanno proprio questo - puoi darle un hash (md5), e sputa un testo in chiaro noto che genera quel particolare hash. Se si dovesse accedere a un database che memorizza gli hash md5, sarebbe banale inserire l'hash per l'amministratore in tale servizio ed effettuare l'accesso. Tuttavia, se le password fossero state salate, tale servizio diventerebbe inefficace.

Inoltre, il double-hashing è generalmente considerato come metodo cattivo, perché diminuisce lo spazio dei risultati. Tutti gli hash popolari sono a lunghezza fissa. Quindi, puoi avere solo un valore finito di questa lunghezza fissa, ei risultati diventano meno vari. Questo potrebbe essere considerato come un'altra forma di salatura, ma non lo raccomanderei.

4
Henrik Paul