Hash e salt sicuri per le password PHP


1174

Attualmente si dice che MD5 è parzialmente non sicuro. Tenendo conto di ciò, vorrei sapere quale meccanismo utilizzare per la protezione con password.

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

Sto usando PHP. Voglio un sistema di crittografia password sicuro e veloce. Hashing di 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 sicuro
  3. Può usare il sale (in questo caso, tutti i sali sono ugualmente buoni? Esiste un modo per generare sali buoni?)

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

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

Domande correlate che non coprono del tutto la mia domanda:

Qual è la differenza tra SHA e MD5 in PHP
Crittografia password semplice
Metodi sicuri per l'archiviazione di chiavi, password per asp.net
Come implementare le password salate in Tomcat 5.5


13
openwall.com/phpass è anche un'ottima libreria
Alfred,

51
Md5 ora è completamente pericoloso
JqueryToAddNumbers il

3
@NSAwesomeGuy Dipende da cosa lo stai usando. È banale abbinare arcobaleno o semplicemente password MD5 non salate a forza bruta, certo, ma con una salata decente è ancora estremamente poco pratico costruire una tabella arcobaleno per decifrare rapidamente set di password, e la forza bruta è un no-hoper.
Craig Ringer,

12
PHP 5.5+ ha un hash di password sicuro incorporato in php.net/manual/en/function.password-hash.php
Terence Johnson

Risposte:


982

DISCLAIMER : questa risposta è stata scritta nel 2008.

Da allora, PHP ci ha dato password_hashe password_verifye, fin dalla loro introduzione, sono la raccomandata hashing delle password e metodo di controllo.

La teoria della risposta è comunque una buona lettura.

TL; DR

cosa non fare

  • Non limitare i caratteri che gli utenti possono inserire per le password. Solo gli idioti lo fanno.
  • Non limitare la lunghezza di una password. Se i tuoi utenti desiderano una frase con supercalifragilisticexpialidocious, non impedire loro di usarla.
  • Non rimuovere o sfuggire a HTML e caratteri speciali nella password.
  • Non archiviare mai la password dell'utente in testo semplice.
  • Non inviare mai una password via e-mail al tuo utente, tranne quando ha perso la sua e ne hai inviata una temporanea.
  • Mai e poi mai registrare le password in alcun modo.
  • Non inserire mai le password con SHA1 o MD5 o SHA256! I cracker moderni possono superare 60 e 180 miliardi di hash / secondo (rispettivamente).
  • Non mescolare bcrypt e con la cruda uscita di hash () , sia in uscita uso esadecimale o base64_encode esso. (Questo vale per qualsiasi input che può avere una canaglia \0, che può indebolire seriamente la sicurezza.)

dos

  • Usa scrypt quando puoi; bcrypt se non puoi.
  • Utilizzare PBKDF2 se non è possibile utilizzare bcrypt o scrypt, con hash SHA2.
  • Ripristina le password di tutti quando il database è compromesso.
  • Implementa una lunghezza minima ragionevole di 8-10 caratteri, oltre a richiedere almeno 1 lettera maiuscola, 1 lettera minuscola, un numero e un simbolo. Ciò migliorerà l'entropia della password, a sua volta rendendola più difficile da decifrare. (Vedi la sezione "Cosa rende una buona password?" Per alcuni dibattiti.)

Perché comunque le password hash?

L'obiettivo dietro le password di hashing è semplice: impedire l'accesso dannoso agli account utente compromettendo il database. Quindi l'obiettivo dell'hash delle password è quello di scoraggiare un hacker o un cracker costando loro troppo tempo o denaro per calcolare le password in chiaro. E i tempi / i costi sono i migliori deterrenti nel tuo arsenale.

Un altro motivo per cui si desidera un hash valido e affidabile su un account utente è darti il ​​tempo sufficiente per cambiare tutte le password nel sistema. Se il tuo database è compromesso, avrai bisogno di tempo sufficiente per bloccare almeno il sistema, altrimenti cambia tutte le password nel database.

Jeremiah Grossman, CTO di Whitehat Security, ha dichiarato sul blog di White Hat Security dopo un recente recupero della password che ha richiesto la rottura della forza di protezione della sua password:

È interessante notare che, vivendo questo incubo, ho imparato MOLTO che non sapevo su cracking, archiviazione e complessità delle password. Ho imparato perché l'archiviazione delle password è molto più importante della complessità delle password. Se non sai come è memorizzata la tua password, tutto ciò di cui puoi veramente fare affidamento è la complessità. Questa potrebbe essere una conoscenza comune di password e professionisti della crittografia, ma per l'esperto medio di InfoSec o Web Security, ne dubito fortemente.

(Enfasi mia.)

Cosa rende comunque una buona password?

Entropia . (Non che sottoscrivo pienamente il punto di vista di Randall.)

In breve, l'entropia è la quantità di variazione all'interno della password. Quando una password è solo lettere latine minuscole, sono solo 26 caratteri. Questa non è molta variazione. Le password alfanumeriche sono migliori, con 36 caratteri. Ma consentire maiuscole e minuscole, con simboli, è di circa 96 caratteri. È molto meglio delle semplici lettere. Un problema è che per rendere memorabili le nostre password inseriamo dei pattern, che riducono l'entropia. Oops!

L'entropia della password si approssima facilmente. L'uso dell'intera gamma di caratteri ascii (circa 96 caratteri tipizzabili) produce un'entropia di 6,6 per carattere, che a 8 caratteri per una password è ancora troppo bassa (52.679 bit di entropia) per la sicurezza futura. Ma la buona notizia è: password più lunghe e password con caratteri unicode aumentano davvero l'entropia di una password e rendono più difficile decifrare.

C'è una discussione più lunga sull'entropia delle password sul sito Crypto StackExchange . Una buona ricerca su Google produrrà anche molti risultati.

Nei commenti ho parlato con @popnoodles, che ha sottolineato che l' applicazione di una politica di password di lunghezza X con molte lettere, numeri, simboli, ecc. X può effettivamente ridurre l'entropia rendendo lo schema delle password più prevedibile. Sono daccordo. La casualità, il più casuale possibile, è sempre la soluzione più sicura ma meno memorabile.

Per quanto ne so, fare la migliore password del mondo è un Catch-22. O non è memorabile, troppo prevedibile, troppo breve, troppi caratteri unicode (difficili da digitare su un dispositivo Windows / Mobile), troppo lunghi, ecc. Nessuna password è davvero abbastanza buona per i nostri scopi, quindi dobbiamo proteggerli come se fossero erano a Fort Knox.

Migliori pratiche

Bcrypt e scrypt sono le migliori pratiche attuali. Scrypt sarà migliore di bcrypt nel tempo, ma non ha visto l'adozione come standard da Linux / Unix o dai server web e non ha ancora pubblicato recensioni approfondite del suo algoritmo. Tuttavia, il futuro dell'algoritmo sembra promettente. Se stai lavorando con Ruby c'è una gemma scrypt che ti aiuterà, e Node.js ora ha il suo pacchetto scrypt . Puoi usare Scrypt in PHP tramite l' estensione Scrypt o l' estensione Libsodium (entrambi sono disponibili in PECL).

Consiglio vivamente di leggere la documentazione per la funzione crypt se vuoi capire come usare bcrypt o trovarti un buon wrapper o usare qualcosa come PHPASS per un'implementazione più legacy. Raccomando un minimo di 12 round di bcrypt, se non da 15 a 18.

Ho cambiato idea sull'uso di bcrypt quando ho saputo che bcrypt utilizza solo il programma chiave di blowfish, con un meccanismo a costo variabile. Quest'ultimo consente di aumentare i costi per forzare la password di una password aumentando il programma di chiavi già costoso di Blowfish.

Pratiche medie

Quasi non riesco più a immaginare questa situazione. PHPASS supporta PHP da 3.0.18 a 5.3, quindi è utilizzabile su quasi tutte le installazioni immaginabili e dovrebbe essere usato se non si è certi che il proprio ambiente supporti bcrypt.

Supponiamo però che non sia possibile utilizzare bcrypt o PHPASS. Cosa poi?

Prova un'implementazione di PDKBF2 con il numero massimo di round che il tuo ambiente / applicazione / percezione dell'utente può tollerare. Il numero più basso che consiglierei è di 2500 colpi. Inoltre, assicurarsi di utilizzare hash_hmac () se è disponibile per rendere più difficile la riproduzione dell'operazione.

Pratiche future

In PHP 5.5 è disponibile una libreria completa di protezione con password che elimina qualsiasi problema di collaborazione con bcrypt. Mentre la maggior parte di noi è bloccata con PHP 5.2 e 5.3 negli ambienti più comuni, in particolare gli host condivisi, @ircmaxell ha creato un livello di compatibilità per l'API in arrivo che è retrocompatibile con PHP 5.3.7.

Riepilogo e dichiarazione di non responsabilità sulla crittografia

Non esiste la potenza di calcolo necessaria per decifrare una password con hash. L'unico modo per i computer di "decifrare" una password è ricrearla e simulare l'algoritmo di hashing utilizzato per proteggerla. La velocità dell'hash è linearmente correlata alla sua capacità di essere forzata brutalmente. Peggio ancora, la maggior parte degli algoritmi di hash può essere facilmente parallelizzata per funzionare ancora più velocemente. Ecco perché schemi costosi come bcrypt e scrypt sono così importanti.

Non puoi prevedere tutte le minacce o le vie di attacco, quindi devi fare del tuo meglio per proteggere gli utenti in anticipo . Se non lo fai, potresti anche perdere il fatto di essere stato attaccato fino a quando non è troppo tardi ... e sei responsabile . Per evitare quella situazione, agire paranoico per cominciare. Attacca il tuo software (internamente) e tenta di rubare le credenziali dell'utente, o modificare gli account di altri utenti o accedere ai loro dati. Se non collaudi la sicurezza del tuo sistema, non puoi incolpare nessuno tranne te stesso.

Infine: non sono un crittografo. Qualunque cosa abbia detto è la mia opinione, ma mi capita di pensare che sia basato sul buon vecchio senso comune ... e su molte letture. Ricorda, sii il più paranoico possibile, rendi le cose più difficili da intromettere il più possibile, quindi, se sei ancora preoccupato, contatta un hacker o un crittografo dal cappello bianco per vedere cosa dicono del tuo codice / sistema.


9
un segreto non aiuta poiché il tuo DB di password dovrebbe essere segreto comunque - se riescono a procurarsi quel DB, possono anche trovare qualunque segreto tu stia usando. è comunque importante che il sale sia casuale.
frankodwyer,

2
nota, non è proprio vero che "il potere computazionale di decifrare" non esiste ancora. poiché la maggior parte delle password sono parole del dizionario o derivate dal dizionario, un attacco basato sul dizionario è di solito molto efficace (da qui l'uso di criteri password e conteggi dell'iterazione).
frankodwyer,

6
@wicked pulce, non sto litigando con te. Indico quanto sia complessa e complessa questa area del nostro lavoro. Continuo a sperare di essere istruito dalle best practice migliori e più intelligenti per la creazione del sistema di gestione dei contenuti di un piccolo sito web. Sto ancora imparando qui. ... ogni volta che leggo qualcosa di sensato, presto noto altri 5 post che lo contraddicono. quel round-and-round diventa vertiginoso rapidamente :)
m42,

4
Revisione interessante. L'ID utente (diciamo, un incremento automatico BIGINT) è un nonce buono? O dal momento che non è casuale non è buono? Inoltre, dovrò archiviare il nonce per ogni utente nel database ... La chiave del sito + nonce + HMAC fornisce una sicurezza significativamente migliorata su un hash salato (con ID utente) ripetuto più volte? Allo stesso modo, l'iterazione di HMAC più volte fa bene alla sicurezza?
luiscubal

4
L'invio di una password temporanea tramite e-mail che richiede all'utente di modificarla la prima volta che la utilizza e l'invio di un collegamento "sicuro" tramite e-mail che consente loro di impostare la password sono ugualmente rischiosi. In entrambi i casi, chiunque intercetti l'e-mail può accedere all'account purché utilizzi il collegamento o la password prima del destinatario previsto.
Tim Gautier,

138

Una risposta molto più breve e sicura : non scrivere affatto il tuo meccanismo di password , usa un meccanismo provato e testato.

  • PHP 5.5 o versione successiva: password_hash () è di buona qualità e parte del core PHP.
  • Versioni precedenti di PHP: la libreria phpass di OpenWall è molto meglio della maggior parte del codice personalizzato, utilizzato in WordPress, Drupal, ecc.

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

Autotest rapido: cos'è lo stretching delle password e quante iterazioni dovresti usare? Se non conosci la risposta, dovresti utilizzare password_hash(), poiché l'estensione della password è ora una caratteristica fondamentale dei meccanismi delle password a causa di CPU molto più veloci e l'uso di GPU e FPGA per decifrare le password a tassi 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. Si tratta di forzatura brutale, ovvero l'enumerazione e il controllo di ogni password di Windows di 8 caratteri , inclusi i caratteri speciali, e non è un attacco di dizionario. Era il 2012, a partire dal 2018 potresti usare un minor numero di GPU o crackare più velocemente con 25 GPU.

Ci sono anche molti attacchi da tavolo arcobaleno alle password di Windows che girano su normali CPU e sono molto veloci. Tutto questo perché Windows continua a non salare o allungare le sue password, anche in Windows 10 - non fare lo stesso errore di Microsoft!

Guarda anche:

  • risposta eccellente con maggiori informazioni sul perché password_hash()o phpasssul modo migliore di procedere.
  • buon articolo di blog che fornisce "fattori di lavoro" raccomandati (numero di iterazioni) per gli algoritmi principali, tra cui bcrypt, scrypt e PBKDF2.

1
ma questi sistemi sono meglio conosciuti e forse già compromessi. ma è meglio crearne uno tuo quando non sai cosa stai facendo.
JqueryToAddNumbers,

14
Ri "questi sistemi sono meglio conosciuti e forse già compromessi" - non c'è motivo per cui un sistema ben progettato per l'autenticazione dovrebbe diventare "già compromesso" solo perché è meglio conosciuto. Le biblioteche come phpass sono scritte da esperti e riviste da molte persone in dettaglio: il fatto che siano ben note accompagna la revisione dettagliata di persone diverse ed è più probabile che significhi che sono sicure.
RichVel,

Dati i recenti dump di hash delle password da LinkedIn, Last.fm e altri, questo è abbastanza attuale. Sei in buona compagnia nel non sapere come scrivere il tuo meccanismo di password!
RichVel

3
@PP - a mio avviso, le probabilità che un algoritmo di hashing delle password sottoposto a revisione paritaria con una backdoor NSA sono molto basse. Le probabilità che qualcuno non sia un vero esperto di crittografia a scrivere un nuovo meccanismo di hashing della password senza altre vulnerabilità sono molto più basse. E la tipica webapp utilizza solo l'hash MD5 o SHA-1, il che è terribile - anche il libro di PHP Security Essential di Chris Shiflett altrimenti eccezionale raccomanda MD5 ...
RichVel

1
@RichVel - La funzione password_hash (). Come accennato in precedenza, è integrato nel core PHP (aka / ext / standard).
CubicleSoft

43

Non memorizzerei la password con hash in due modi diversi, perché il sistema è almeno debole come il più debole degli algoritmi di hash in uso.


non per l'hash della password. l'attaccante deve solo rompere un hash per recuperare la password. il punto è discutibile in quanto né MD5 né SHA1 hanno interruzioni pratiche disponibili nello scenario di password.
frankodwyer,

2
scusa, ho letto male la tua risposta come raccomandando di usare due hash ... in effetti hai ragione. L'uso di due hash indebolisce il sistema nel caso della password, poiché devono solo rompere l'hash più debole.
frankodwyer,

40

A partire da PHP 5.5, PHP ha funzioni semplici e sicure per l'hash e la verifica di 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 password_hash()viene utilizzato, genera un salt casuale e lo include nell'hash emesso (insieme al costo e all'algoritmo utilizzati), password_verify()quindi legge tale hash e determina il metodo salt e di crittografia utilizzato e lo verifica rispetto alla password in chiaro fornita.

Fornire a PASSWORD_DEFAULTPHP istruzioni 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 dei più potenti algoritmi disponibili.

L'aumento dei costi (il cui valore predefinito è 10) rende più difficile l'hash della forza bruta ma significa anche generare hash e verificare le password contro di loro sarà più lavoro per la CPU del tuo server.

Si noti che anche se l'algoritmo di hashing predefinito può cambiare, i vecchi hash continueranno a verificare bene perché l'algoritmo utilizzato è memorizzato nell'hash e lo password_verify()raccoglie.


33

Sebbene alla domanda sia stata data una risposta, voglio solo ribadire che i sali utilizzati per l'hash dovrebbero essere casuali e non come l'indirizzo e-mail come suggerito nella prima risposta.

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

Recentemente ho discusso se gli hash delle password salati con bit casuali sono più sicuri di quelli salati con sali indovinabili o noti. Vediamo: se il sistema che memorizza la password è compromesso così come il sistema che memorizza il salt casuale, l'attaccante avrà accesso all'hash e al salt, quindi se il salt è casuale o no, non importa. L'attaccante può generare tabelle arcobaleno pre-calcolate per rompere l'hash. Ecco la parte interessante: non è così banale generare tabelle pre-calcolate. Facciamo un esempio del modello di sicurezza WPA. La password WPA in realtà non viene mai inviata al punto di accesso wireless. Invece, è hash con il tuo SSID (il nome della rete, come Linksys, Dlink ecc.). Un'ottima spiegazione di come funziona è qui. Per recuperare la password dall'hash, dovrai conoscere la password e salt (nome della rete). Church of Wifi ha già pre-calcolato le tabelle hash con i migliori 1000 SSID e circa 1 milione di password. La dimensione è di tutti i tavoli è di circa 40 GB. Come puoi leggere sul loro sito, qualcuno ha usato 15 array FGPA per 3 giorni per generare queste tabelle. Supponendo che la vittima stia utilizzando l'SSID come "a387csf3" e la password come "123456", verrà craccato da quelle tabelle? No! .. non può. Anche se la password è debole, le tabelle non hanno hash per SSID a387csf3. Questa è la bellezza di avere il sale casuale. Deterrerà i cracker che prosperano su tavoli pre-calcolati. Può fermare un determinato hacker? Probabilmente no. Ma l'uso di sali casuali fornisce un ulteriore livello di difesa. Mentre siamo su questo argomento, parliamo del vantaggio aggiuntivo di memorizzare sali casuali su un sistema separato. Scenario n. 1: gli hash delle password sono memorizzati sul sistema X e i valori salt utilizzati per l'hash sono memorizzati sul sistema Y. Questi valori salati sono indovinabili o noti (ad es. Nome utente) Scenario n. 2: gli hash password sono memorizzati sul sistema X e i valori salt utilizzati per gli hash sono memorizzati sul sistema Y. Questi valori di salt sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi immaginare, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (Scenario n. 2). L'attaccante dovrà indovinare i valori di addizione per riuscire a rompere gli hash. Se viene utilizzato un sale a 32 bit, saranno necessarie 2 ^ 32 = 4.294.967.296 (circa 4,2 miliardi) di iterazioni per ogni password indovinata. Gli hash delle password sono memorizzati sul sistema X e i valori salt utilizzati per l'hash sono memorizzati sul sistema Y. Questi valori salt sono ipotizzabili o noti (ad es. Nome utente) Scenario 2: gli hash password sono memorizzati sul sistema X e i valori salt utilizzati per l'hash sono memorizzati su sistema Y. Questi valori di sale sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi immaginare, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (Scenario n. 2). L'attaccante dovrà indovinare i valori di addizione per riuscire a rompere gli hash. Se viene utilizzato un sale a 32 bit, saranno necessarie 2 ^ 32 = 4.294.967.296 (circa 4,2 miliardi) di iterazioni per ogni password indovinata. Gli hash delle password sono memorizzati sul sistema X e i valori salt utilizzati per l'hash sono memorizzati sul sistema Y. Questi valori salt sono ipotizzabili o noti (ad es. Nome utente) Scenario 2: gli hash password sono memorizzati sul sistema X e i valori salt utilizzati per l'hash sono memorizzati su sistema Y. Questi valori di sale sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi immaginare, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (Scenario n. 2). L'attaccante dovrà indovinare i valori di addizione per riuscire a rompere gli hash. Se viene utilizzato un sale a 32 bit, saranno necessarie 2 ^ 32 = 4.294.967.296 (circa 4,2 miliardi) di iterazioni per ogni password indovinata. Questi valori di sale sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi immaginare, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (Scenario n. 2). L'attaccante dovrà indovinare i valori di addizione per riuscire a rompere gli hash. Se viene utilizzato un sale a 32 bit, saranno necessarie 2 ^ 32 = 4.294.967.296 (circa 4,2 miliardi) di iterazioni per ogni password indovinata. Questi valori di sale sono casuali. Nel caso in cui il sistema X sia stato compromesso, come puoi immaginare, c'è un enorme vantaggio nell'usare il sale casuale su un sistema separato (Scenario n. 2). L'attaccante dovrà indovinare i valori di addizione per riuscire a rompere gli hash. Se viene utilizzato un sale a 32 bit, saranno necessarie 2 ^ 32 = 4.294.967.296 (circa 4,2 miliardi) di iterazioni per ogni password indovinata.


7
Anche se l'attaccante ottiene il sale, una stringa "sitesalt: usersalt: password" è ancora resistente alle tabelle pre-calcolate, poiché l'attaccante deve generare le tabelle per ogni utente (quindi l'attacco diventa molto più lento), a meno che ovviamente un utente specifico viene preso di mira ...
luiscubal,

Per quanto riguarda "Anche se l'attaccante ottiene il sale, una stringa" sitesalt: usersalt: password "è ancora resistente alle tabelle pre-calcolate", totalmente d'accordo. Il mio punto è che sitesalt, se reso casuale e lungo, renderà il sistema più sicuro di quanto sia prevedibile. Ho visto alcune persone raccomandare l'uso dell'id e-mail ecc. Come salt, e lo scoraggio.
Gaurav Kumar,

Ti sei perso quello che ho scritto in origine. Ho detto di usare un nonce casuale, memorizzato con il record, PIÙ l'indirizzo e-mail. L'aggiunta dell'indirizzo e-mail rende l'entropia extra su cui l'hacker può lavorare. Da allora ho riscritto la mia risposta a favore di bcrypt.
Robert K,

28

Voglio solo sottolineare che PHP 5.5 include un'API di hashing della password che fornisce un wrapper 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 puoi semplicemente requireusare), per coloro che usano PHP 5.3.7 e versioni successive e vogliono usarlo subito.

Supporta solo BCRYPT per ora, ma mira ad essere facilmente esteso per includere altre tecniche di hashing delle password e poiché la tecnica e il costo sono memorizzati come parte dell'hash, le modifiche alla tua tecnica / costo di hashing preferito non invalideranno gli hash correnti, il framework utilizzerà automagicamente la tecnica / i costi corretti 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 password
  • password_needs_rehash()- controlla se l'hash specificato corrisponde alle opzioni fornite. Utile per verificare se l'hash è conforme alla tua attuale tecnica / schema dei costi che ti consente di ripetere la revisione, 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 PHP più recenti quando sono supportati algoritmi di hashing più recenti e più forti." L'uso di PASSWORD_DEFAULT e password_needs_rehash () all'accesso (e, se necessario, ripassare) dovrebbe garantire che gli hash siano ragionevolmente resistenti agli attacchi di forza bruta con poco o nessun lavoro per te.

EDIT: ho appena capito che questo è menzionato brevemente nella risposta di Robert K. Lascio qui questa risposta 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.


19

Sto usando Phpass che è una semplice classe PHP a un file che potrebbe essere implementata molto facilmente in quasi tutti i progetti PHP. Vedere anche The H .

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

L'hash restituito potrebbe essere archiviato nel database così com'è. L'uso di esempio per generare l'hash è:

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

Per verificare la password, è possibile utilizzare:

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

14

COSE DA RICORDARE

Molto è stato detto sulla crittografia delle 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 delle password assicurati di avere i seguenti implementati o pronti per essere implementati.

SERVER

PORTS

Non importa quanto sia valida la tua crittografia se non proteggi correttamente il server che esegue PHP e DB tutti i tuoi sforzi sono inutili. La maggior parte dei server funziona relativamente allo stesso modo, hanno porte assegnate per permetterti di accedervi da remoto tramite ftp o shell. Assicurati di cambiare la porta predefinita di qualsiasi connessione remota tu abbia attivo. Non facendo ciò, in effetti hai fatto in modo che l'attaccante facesse un altro passo nell'accesso al tuo sistema.

NOME UTENTE

Per tutto ciò che è buono nel mondo non utilizzare il nome utente admin, root o qualcosa di simile. Inoltre, se si utilizza 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 buone password per evitare di essere violato, fai lo stesso. Qual è il punto di passare attraverso tutto lo sforzo di bloccare la porta d'ingresso quando la porta posteriore è spalancata.

BANCA DATI

SERVER

Idealmente vuoi il tuo DB e APPLICAZIONE su server separati. Ciò 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

Avere sempre la propria applicazione con un proprio account per accedere al DB e assegnargli solo i privilegi di cui avrà bisogno.

Quindi avere un account utente separato per te che non è archiviato in nessun punto del server, nemmeno nell'applicazione.

Come sempre NON rendere questa radice o qualcosa di simile.

PAROLA D'ORDINE

Segui le stesse linee guida di tutte le buone password. Inoltre, non riutilizzare la stessa password su nessun account SERVER o DB sullo stesso sistema.

PHP

PAROLA D'ORDINE

MAI MAI archiviare una password nel tuo DB, invece memorizza l'hash e il salt unico, spiegherò perché in seguito.

hashing

HASHING ONE WAY !!!!!!!, mai hash una password in modo che possa essere invertita, gli hash dovrebbero essere un modo, il che significa che non li invertire e confrontarli con la password, invece si ha la password inserita allo stesso modo e confronta i due hash. Ciò significa che anche se un utente malintenzionato ottiene l'accesso al DB non sa quale sia effettivamente la password, solo il suo hash risultante. Ciò significa maggiore sicurezza per i tuoi utenti nel peggiore scenario possibile.

Ci sono un sacco di buone funzioni di hashing là fuori ( password_hash, hash, ecc ...), ma è necessario selezionare un algoritmo di buono per l'hash per essere efficace. (bcrypt e altri simili sono algoritmi decenti.)

Quando la velocità di hashing è la chiave, più lenta è la più resistente agli attacchi di Brute Force.

Uno degli errori più comuni nell'hash è che gli hash non sono unici per gli utenti. Questo principalmente perché i sali non sono generati in modo univoco.

SALATURA

Le password devono sempre essere salate prima dell'hash. Salating aggiunge una stringa casuale alla password in modo che password simili non appaiano uguali nel DB. Tuttavia, se il sale non è univoco per ciascun utente (ad esempio: si utilizza un sale con codice rigido), è quasi impossibile rendere il sale inutile. Perché una volta che un utente malintenzionato scopre una password salt, ha il sale per tutti.

Quando crei un salt assicurati che sia univoco per la password che sta salando, quindi archivia l'hash e salt completati nel tuo DB. Ciò che farà è farlo in modo che un utente malintenzionato debba rompere individualmente ogni sale e hash prima di poter ottenere l'accesso. Ciò significa molto più tempo e lavoro per l'attaccante.

UTENTI CHE CREANO PASSWORD

Se l'utente sta creando una password attraverso il frontend, ciò 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 tutta la tua sicurezza in PHP è inutile. Trasmetti SEMPRE i dati in SICUREZZA, questo avviene tramite SSL, ma fai attenzione anche se SSL non è perfetto (il difetto 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 ne sarà grato alla fine.

Infine, indipendentemente dal fatto che le misure di sicurezza adottate non siano sicure al 100%, tanto più avanzata è la tecnologia da proteggere tanto più avanzati diventano gli attacchi. Ma seguire questi passaggi renderà il tuo sito più sicuro e molto meno desiderabile per gli aggressori.

Ecco una classe PHP che crea facilmente hash e salt per una password

http://git.io/mSJqpw


1
Dovresti colpire SHA512 dal tuo elenco di algoritmi hash decenti, perché è troppo veloce. Usalo solo in combinazione con PBKDF2. Mentre BCrypt si basa sul pesce palla, il pesce palla stesso è un algoritmo per la crittografia, non per l'hashing.
martinstoeckli,

1
Come si memorizza il sale casuale nel DB? Penso che non lo hash (non può essere utilizzato per la verifica) né archiviare in modo chiaro (nessun vantaggio reale se l'attaccante è in grado di leggere il DB). Quindi, come lo fai?
Iazel,

wmfrancia ha scritto: "Salting aggiunge una stringa casuale alla password in modo che password simili non appaiano uguali nel DB". Questo non ha senso per me. Gli hash nel DB appariranno già diversi perché questa è una proprietà delle funzioni hash.
H2ONaCl

wmfancia ha scritto a proposito di un sale costante: "una volta che un utente malintenzionato scopre una password salt ha il sale per tutti". Lo stesso si può dire che se l'hacker scopre quale campo DB è il sale, ha i sali per tutti loro. Dal momento che un sale costante probabilmente non si troverebbe nel DB, questo è positivo per un sale costante.
H2ONaCl

Naturalmente, questi commenti non suggeriscono che un sale casuale per utente non sia migliore di un sale per applicazione. È meglio.
H2ONaCl

12

Google afferma che SHA256 è disponibile per PHP.

Dovresti assolutamente usare un sale. Consiglierei di usare byte casuali (e non limitarti a caratteri e numeri). Come al solito, più a lungo scegli, più sicuro, più lento diventa. 64 byte dovrebbero andare bene, immagino.


13
64 bit dovrebbero essere sufficienti per chiunque?
Konerak,

@Konerak, ci tornerei dopo 20 anni. :) Ma sì SHA256 è davvero disponibile. Se vuoi sapere quanto è sicuro SHA256, potresti dare un'occhiata: security.stackexchange.com/questions/90064/…
Vincent Edward Gedaria Binua,

8

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


2
l'hashing multiplo protegge anche dagli attacchi del dizionario e della forza bruta, vale a dire che richiede semplicemente più tempo per il calcolo.
frankodwyer,

6
il doppio hashing non ti darà un vantaggio significativo ma le iterazioni di hashing multi round sono ancora una difesa fattibile contro gli attacchi del dizionario e della forza bruce. Gli hash delle password di resistenza industriale utilizzano più di 1000 colpi. PBKDF1 di PKCS # 5 suggerisce un minimo di 1000 colpi.
Berk D. Demir,

8

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

Ci dai una soluzione senza utilizzo e senza utilizzo
Michael,

6

Di solito uso SHA1 e salt con l'ID utente (o qualche altra informazione specifica dell'utente), e talvolta uso anche un sale costante (quindi ho 2 parti sul sale).

Anche SHA1 è ora considerato in qualche modo compromesso, ma in misura molto inferiore 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 tabella arcobaleno cercando l'hash). Un attaccante potrebbe concepibilmente generare una tabella arcobaleno usando il tuo sale, quindi è per questo che dovresti includere un sale specifico dell'utente. In questo modo, dovranno generare una tabella arcobaleno per ogni singolo record nel tuo sistema, non solo per l'intero sistema! Con quel tipo di salatura, anche MD5 è abbastanza sicuro.


2
il sale costante non è una grande idea ... probabilmente non è un difetto fatale ma indebolisce inutilmente lo schema.
frankodwyer,

MD5 e SHA1 sono veloci, quindi questo è un brutto diea.
Codici InCos

4

SHA1 e un sale dovrebbero essere sufficienti (a seconda, naturalmente, se stai codificando qualcosa per Fort Knox o un sistema di accesso per la tua lista della spesa) per il prossimo futuro. Se SHA1 non è abbastanza buono per te, usa SHA256 .

L'idea di un sale è di bilanciare i risultati di hashing, per così dire. È noto, ad esempio, che l'hash MD5 di una stringa vuota è d41d8cd98f00b204e9800998ecf8427e. Quindi, se qualcuno con una memoria abbastanza buona vedrebbe quell'hash e sapesse che è l'hash di una stringa vuota. Ma se la stringa è salata (diciamo, con la stringa " MY_PERSONAL_SALT"), l'hash per la "stringa vuota" (cioè " MY_PERSONAL_SALT") diventa aeac2612626724592271634fb14d3ea6, quindi non ovvio da tornare indietro. Quello che sto cercando di dire è che è meglio usare qualsiasi sale, piuttosto che non. Pertanto, non è troppo importante sapere quale sale usare.

In realtà ci sono siti Web che fanno proprio questo : puoi dargli un hash (md5) e sputa un testo in chiaro noto che genera quel particolare hash. Se avessi accesso a un database che memorizza semplici hash md5, sarebbe banale per te inserire l'hash per l'amministratore di tale servizio e accedere. Ma, se le password fossero salate, tale servizio diventerebbe inefficace.

Inoltre, il doppio hashing è generalmente considerato un metodo errato, poiché riduce lo spazio del risultato. Tutti gli hash popolari sono a lunghezza fissa. Pertanto, è possibile avere solo valori finiti di questa lunghezza fissa e i risultati diventano meno vari. Questo potrebbe essere considerato come un'altra forma di salatura, ma non lo consiglierei.


Il sito di destinazione non dovrebbe contenere nulla di troppo sensibile (non è una banca), ma preferirei comunque proteggerlo.
luiscubal

1
il doppio hashing non riduce lo spazio dei risultati. l'hash iterativo è un controllo comune contro gli attacchi del dizionario e della forza bruta (li rallenta molto più di quanto rallenta il controllo della password).
frankodwyer,

2
@frankodwyer: sì, è male. sha1(sha1($foo))riduce efficacemente lo spazio di uscita, poiché qualsiasi collisione della funzione interna diventerà automaticamente una collisione di quella esterna. Il degrado è lineare, ma è ancora una preoccupazione. I metodi di hashing iterativi restituiscono i dati in ogni round, ad esempio $hash = sha1(sha1($salt . $password) . $salt). Ma non va ancora bene ... Stick con PBKDF2 o Bcrypt ...
ircmaxell,

-7

ok nell'ideale abbiamo bisogno di sale, il sale deve essere unico, quindi lascialo 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);
    }

così 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 dobbiamo salvare nel database il nostro valore della variabile $ hash_psw e la variabile $ salt

e per autorizzare utilizzeremo gli stessi passaggi ...

è 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 con hash in futuro quando devi autorizzare l'utente ...


4
Questa domanda riguardava gli hash per le password. 1 esecuzione di sha512(anche se salato) è ampiamente considerata non abbastanza buona per la protezione con password. (anche che RNG non è crittograficamente sicuro, quindi usarlo per la generazione di password è rischioso).
luiscubal,

2
Non hai idea di cosa stai facendo. Leggi le risposte migliori in questo post e puoi vedere perché il tuo codice non è solo insicuro, ma non ha senso.
criptico ツ

ok. il mio codice non è sicuro. fammi sapere perché stai usando nei tuoi algoritmi ony sha256 ??? So che sha512 è il migliore perché non usarlo ???
Shalvasoft,

1
@shalvasoft sha512 è abbastanza buono per l'hashing generico, ma la protezione con password richiede hash con proprietà molto specifiche ("essere lento" è stranamente una cosa buona , per esempio, e sha512 è piuttosto veloce). Alcune persone hanno usato sha512 come blocco predefinito per creare funzioni di hashing della password, ma al giorno d'oggi l'approccio raccomandato è "usa bcrypt e tieni d'occhio scrypt".
luiscubal,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.