security Sicuro hash e sale per le password di PHP



7 Answers

Una risposta molto più breve e più sicura : non scrivere affatto il proprio meccanismo di password , utilizzare un meccanismo collaudato.

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 critica 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 a 8 caratteri in 6 ore utilizzando 25 GPU installate in 5 PC desktop. Questo è brute-forcing cioè enumerare e controllare ogni password di Windows di 8 caratteri , inclusi caratteri speciali, e non è un attacco di dizionario. Era il 2012, dal 2018 potresti utilizzare un minor numero di GPU o craccare più velocemente con 25 GPU.

Ci sono anche molti attacchi di rainbow table su password di Windows che girano su CPU ordinarie e sono molto veloci. Tutto ciò è dovuto al fatto che Windows non salta o non allunga le sue password, anche in Windows 10 - non commettere lo stesso errore di Microsoft!

Guarda anche:

  • risposta eccellente con ulteriori informazioni 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.
php security passwords hash protection

Attualmente è stato detto che MD5 è parzialmente insicuro. Tenendo conto di ciò, mi piacerebbe sapere quale meccanismo utilizzare per la protezione con password.

Questa domanda è "double hashing" una password meno sicura rispetto alla semplice hashing di una volta? suggerisce che l'hashing di più volte può essere una buona idea, considerando 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 delle 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, vorrei 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




A partire da PHP 5.5, PHP ha funzioni semplici e sicure per l'hashing e la verifica delle password, php.net/manual/en/function.password-hash.php 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 viene usato password_hash() , genera un salt casuale e lo include nell'hash outputtato (insieme al costo e all'algoritmo utilizzato). password_verify() legge quindi l'hash e determina il metodo salt e di crittografia utilizzato, e lo verifica contro la password in chiaro in dotazione.

Fornendo PASSWORD_DEFAULT richiede a PHP di utilizzare l'algoritmo di hashing predefinito della versione di PHP installata. 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.

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




Voglio solo sottolineare che PHP 5.5 include un'API di hashing della password che fornisce un wrapper attorno a crypt() . Questa API semplifica notevolmente 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 è require semplicemente utilizzare), per coloro che usano PHP 5.3.7 e versioni successive e vogliono usarlo al momento.

Supporta BCRYPT solo 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 / costo dell'hash preferito non invalidano gli hash correnti, il framework sarà automagicamente, utilizzare la tecnica / 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 il dato hash corrisponde alle opzioni date. Utile per verificare se l'hash è conforme al tuo schema di tecnica / costo attuale che ti consente di eseguire nuovamente il cambio 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 di PHP più recenti 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 a forza bruta con poco o nessun lavoro per te.

EDIT: Ho appena realizzato che questo è menzionato 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.




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 essere implementato.

SERVER

PORTS

Non importa quanto sia buona la crittografia se non si protegge adeguatamente il server che esegue PHP e DB, tutti i vostri 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. In caso contrario, in effetti l'utente malintenzionato ha fatto un passo in meno nell'accedere al sistema.

NOME UTENTE

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 fare delle buone password per evitare di essere violati, fare lo stesso. Qual è il punto in cui passa tutto lo sforzo di bloccare la porta principale quando hai la backdoor spalancata.

BANCA DATI

SERVER

Idealmente si desidera il DB e l'APPLICAZIONE su server separati. Ciò non è sempre possibile a causa dei costi, ma consente una certa sicurezza in quanto l'utente malintenzionato dovrà eseguire 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. Il che significa maggiore sicurezza per i tuoi utenti nel peggiore scenario possibile.

Esistono molte buone funzioni di hashing ( password_hash , hash , ecc ...) 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.

SALATURA

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à sarà fare in modo che un attaccante debba crackare singolarmente ogni sale e hash prima che possano accedervi. 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 al fatto che tutta la sicurezza in PHP non ha alcun valore. Trasmetti SEMPRE 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, niente è sicuro al 100%, più avanzata sarà 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 per una password facilmente

http://git.io/mSJqpw




Ho trovato l'argomento perfetto su questo argomento qui: https://crackstation.net/hashing-security.htm , volevo che tu ne traggessi beneficio, qui c'è anche il codice sorgente che previene anche attacchi contro il 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));
}
?>



Di solito uso SHA1 e sale con l'ID utente (o qualche altra informazione specifica dell'utente), 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 una tabella arcobaleno generica per attaccare i tuoi hash (alcune persone hanno persino avuto successo usando Google come una sorta di tavolo arcobaleno cercando l'hash). Un utente malintenzionato potrebbe in teoria generare una tabella arcobaleno utilizzando il tuo sale, ecco perché è necessario includere un sale specifico per l'utente. In questo modo, dovranno generare una tabella arcobaleno per ogni record del tuo sistema, non solo uno per l'intero sistema! Con questo tipo di salatura, anche MD5 è decentemente sicuro.




ok nel modo in cui abbiamo bisogno di sale deve essere unico quindi lasciatelo generare

   /**
     * Generating string
     * @param $size
     * @return string
     */
    function Uniwur_string($size){
        $text = md5(uniqid(rand(), TRUE));
        RETURN substr($text, 0, $size);
    }

inoltre abbiamo bisogno dell'hash che sto usando sha512 è il migliore ed è in php

   /**
     * Hashing string
     * @param $string
     * @return string
     */
    function hash($string){
        return hash('sha512', $string);
    }

quindi ora possiamo usare queste funzioni per generare password sicure

// generating unique password
$password = Uniwur_string(20); // or you can add manual password
// generating 32 character salt
$salt = Uniwur_string(32);
// now we can manipulate this informations

// hashin salt for safe
$hash_salt = hash($salt);
// hashing password
$hash_psw = hash($password.$hash_salt);

ora abbiamo bisogno di salvare nel database il nostro valore variabile $ hash_psw e variabile $ salt

e per autorizzare useremo gli stessi passi ...

è il modo migliore per proteggere le password dei nostri clienti ...

Ps per gli ultimi 2 passaggi puoi usare il tuo algoritmo ... ma assicurati di poter generare questa password hash in futuro quando devi autorizzare l'utente ...




Related