Che cosa c'è di buono / cattivo in questo hashing della password personalizzato?

2

Per la cronaca, questo era puramente a scopo di apprendimento, mi è stato detto di non usarlo nemmeno per un sito web personale che non mi aspetto che qualcuno possa visitare, quindi questo post è, purtroppo, l'ultimo che vedrò di questo codice. Tuttavia, ho fatto tutte le cose che ho letto e mi sembra soddisfacente (ma non sono un esperto), quindi sono solo curioso di sapere quali parti potrebbero essere abbastanza brutte da consigliare a tutti di non fare mai mai usare una soluzione personalizzata?
Non nominare nessuno, ma sono abbastanza sicuro di aver già fatto un miglio lavoro migliore del webhost gratuito che inizia con un haha triplo numero, la mia password in chiaro è stata rubata da lì.

Ecco l'idea di base di ciò che ho fatto:

Salt e IV
Ogni sale è generato da una funzione casuale ma non crittograficamente sicura in PHP (è comunque meglio del caso casuale predefinito). Viene quindi crittografato con blowfish utilizzando una chiave definita nel codice e una IV definita in un file effettivo (protetto da htaccess). Il valore crittografato è memorizzato, quindi è molto semplice cambiare la chiave IV o salt per invalidare tutte le password. Inoltre, se il database è compromesso, i sali non possono essere decifrati senza accedere al file system.

Hash
Utilizza lo stretching chiave e sha512. La quantità di allungamento della chiave è definita da un modulo di un valore crc32 della password e sale, quindi ogni utente ha una quantità diversa e è possibile modificare il valore per consentire tempi di elaborazione più lunghi. Ogni hash di ripetizione usa alcuni hash al suo interno nel tentativo di mantenerlo abbastanza casuale.

Ecco il codice reale che ho, se non conosci PHP è ancora abbastanza facile vedere cosa sta succedendo una volta per volta:

$salt_key = 'íSgüý[Îaí²zÿCV™F÷œDDa©^fU©êm‹“.Ù   ®Kâ³ÃX}rÿ,¢\ˆÿ7L³¢QÆH’YeTsÙõŸ¥éÙí#W—c´VÆ';

function get_iv(){
    // It stores it as a file, but there's no point showing that part so here's the actual code bit
    return mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_BLOWFISH, MCRYPT_MODE_CBC), MCRYPT_RAND);
}

function generate_salt(){
    global $salt_key;
    $salt = substr(uniqid(mt_rand(), true), 0, 32);
    $key = hash('sha256', $salt_key, true);
    $iv = get_iv();
    $encrypt = mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $salt, MCRYPT_MODE_CFB, $iv);
    return array($salt, $encrypt);
}

function decrypt_salt($encrypted){
    global $salt_key;
    $key = hash('sha256', $salt_key, true);
    $iv = get_iv();
    return mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $encrypted, MCRYPT_MODE_CFB, $iv);
}

function hash_password($password, $salt){
    #return hash('sha512', $password.$salt, true);
    $hash = $salt;
    for($i=0; $i<(crc32($salt.$password) % 129197); $i++){
        $hash = hash('sha512', $hash.$password.$salt.hash('sha512', $salt.$hash.$password).md5($salt.md5($password.$hash)), true);
    }
    return $hash;
}

La parte per verificare se la password è valida in pratica controlla semplicemente il nuovo hash rispetto a quello vecchio, quindi l'ho lasciato fuori. L'unico svantaggio basato sulle cose che ho letto che un buon algoritmo dovrebbe fare, è che non usa molta memoria.

    
posta Peter 13.10.2016 - 18:11
fonte

2 risposte

4

Domande aperte:

  • Perché non usi un RNG crittograficamente sicuro per il sale? Non le genererai così frequentemente da rischiare di svuotare il pool di entropia del sistema su un sistema moderno.
  • Come è stata generata la chiave di crittografia salt?
  • Quanto è lungo il tuo salt_key (prima di averlo cancellato)?
  • Perché stai tagliando il tuo salt_key ? Ciò non aggiunge sicurezza.
  • Perché l'hashing nidificato troppo complicato (incluso l'uso di MD5 , di tutte le cose) nel tuo ciclo di allungamento delle chiavi? Mi viene in mente Il commento di Moxie Marlinspike sullo schema (spezzato) di MS-CHAP v2 (cerca la stringa" complessità non necessaria ").

Problemi notevoli:

  • In effetti, vuoi usare salti casuali (e IV) in modo sicuro. Implica quanto sia prevedibile il sale; i sali prevedibili consentono agli utenti malintenzionati di calcolare preventivamente le tabelle di ricerca per i sali previsti rispetto alle password probabili. Le IV prevedibili sono probabilmente meno rischiose in questo contesto, ma non c'è alcun motivo non per usare quelli casuali in modo sicuro.
  • Il tuo algoritmo di allungamento della chiave ti fornisce un aumento minimo della sicurezza - per ogni password di prova, l'attaccante può calcolare il conteggio dell'iterazione bene, supponendo che sappia il sale (e se non lo fanno allora non possono prova a forzare bruscamente il verificatore della password) e ti espone al rischio di eseguire molti meno cicli di hashing di quanto tu non voglia. In particolare, se il CRC è un multiplo esatto di 127197, il sale dell'utente viene memorizzato come verificatore della password e la password non viene utilizzata affatto, quindi qualsiasi password funzionerà per quell'utente! se ottieni un milione di utenti, circa 8 di loro avranno nessuna protezione con password .
  • Non hai alcun metodo per ruotare o aggiornare l'algoritmo per la verifica della password, almeno non visibile in quello che hai presentato qui. Gli attributi critici hardcoded (come la chiave, le primitive crittografiche e il modo in cui viene determinato il conteggio dell'iterazione) potrebbero dover essere modificati in futuro, a quel punto sarà necessario essere in grado di verificare la password di un utente con lo schema precedente prima di generare un nuovo verificatore di password con il nuovo schema (a meno che non si intenda forzare tutti a reimpostare la propria password, il che è un problema e dovrebbe essere fatto solo quando c'è motivo di aspettarsi che i vecchi siano compromessi). Pertanto, è necessario un modo per specificare una versione dell'algoritmo di verifica della password, o almeno è necessario memorizzare identificatori (probabilmente indici) per i vari valori attualmente costanti e osservare i valori in base all'identificatore / indice di versione memorizzati di ciascun utente. li>
  • Nel peggiore dei casi, 129 + k iterazioni di SHA-512 (non importa se SHA512 (SHA512 (MD5 (MD5))) impiegherà molto tempo sul server. Un utente malintenzionato che trova una combinazione di nome utente e password per cui è così costoso calcolare il verificatore può semplicemente inviare un gruppo di richieste con credenziali del genere (soprattutto perché, a causa della reversibilità di CRC, l'utente malintenzionato può manipolare l'input per ottenere esattamente il checksum desiderato). Questo probabilmente causerà un denial-of-service sul tuo server. I fattori di lavoro per la verifica della password devono essere sufficientemente elevati da rallentare la forzatura bruta, ma non devono essere sufficientemente elevati da consentire a un utente malintenzionato di sovraccaricare un server.
risposta data 14.10.2016 - 03:23
fonte
1

Una cosa negativa a riguardo è che è complicato e qualsiasi sviluppatore che aderisce al progetto non sarà in grado di dire facilmente se è sicuro, a meno che non si prenda il tempo di leggerlo e comprenderlo. Se si preoccupano della sicurezza e della qualità del sistema in generale, possono essere motivati a prendere quel tempo anche se non è necessario per le loro attività immediate.

La soluzione semplice, in PHP 5.5 o versioni successive, è di utilizzare semplicemente il password_hash e password_verify funzioni.

    
risposta data 15.03.2018 - 23:11
fonte

Leggi altre domande sui tag