2013-02-05 15 views
15

Sto usando crypt() in password hash in PHP e sto cercando di elaborare il modo più sicuro di testare l'uguaglianza dell'hash risultante durante l'esecuzione di controlli password .strcmp vs. == vs. === in PHP per il controllo dell'uguaglianza hash

ci sono tre opzioni che posso vedere:

Opzione 1 - Doppia Equals

function checkPassword($hash, $password) 
{ 
    return crypt($password, $hash) == $hash; 
} 

Opzione 2 - Triple Equals

function checkPassword($hash, $password) 
{ 
    return crypt($password, $hash) === $hash; 
} 

Opzione 3-strcmp()

function checkPassword($hash, $password) 
{ 
    return strcmp(crypt($password, $hash), $hash) === 0; 
} 

Il mio intuito mi dice che l'opzione 1 è una cattiva idea, a causa della mancanza di controllo del tipo, e che le opzioni 2 o 3 sono probabilmente migliori. Tuttavia, non riesco a capire se c'è un caso specifico che === o strcmp non riuscirebbe. Quale è più sicuro per questo scopo?

+1

Leggilo: http://raz0r.name/vulnerabilities/simple-machines-forum/ – user956584

+0

@Userpassword Bug interessante! Mi chiedo come PHP gestisca stringhe come '$ 2a $ 10 $ ... $' quando le cast come numeri ... – Polynomial

+0

Se vuoi semplicemente confrontare gli hash in modo affidabile, usa semplicemente '==='. Se ti preoccupi veramente della sicurezza e dei potenziali attacchi temporali (anche a dispetto del jitter di rete), dovresti dare un'occhiata a [questo] (https://github.com/delight-im/Faceless/issues/4) o [this] (https://github.com/delight-im/Faceless/pull/5) discussione o utilizzare la funzione 'hash_equals()' (PHP 5.6+). – caw

risposta

19

Quando si tratta di sicurezza, preferisco utilizzare l'operatore ===. === assicura che i due operandi siano esattamente gli stessi, senza tentare di adattarsi al casting per "aiutare" il confronto a raggiungere una corrispondenza riuscita - in quanto può aiutare durante lo sviluppo grazie a un linguaggio a caratteri liberi, come PHP.

Naturalmente, ci si deve fidare di uno degli operandi. Un hash dal database è affidabile, mentre l'input dell'utente non lo è.

Uno può sempre dither per un po ', arrivando alla conclusione non vi è alcun rischio utilizzando == in un caso specifico. Può essere. Ma per esempio

"0afd9f7b678fdefca" == 0 is true 
    "aafd9f7b678fdefca" == 0 is also true 

PHP tenta di convertire il "hash" in un numero (probabilmente utilizzando atoi), che dà 0. Mentre è improbabile crypt restituisce 0, preferirei di massimizzare i casi in cui le password non corrispondono (e rispondono a una chiamata di supporto) utilizzando ===, che consente un caso raro a cui non ho pensato utilizzando ==.

Per quanto riguarda strcmp, la funzione restituisce <0 o >0 se diversa e 0 se uguale. Ma

strcmp("3", 0003) returns 0 
    strcmp("0003", 0003) returns -3 

che non sono sorprendente, dopo tutto.Un valore letterale 0003 è in realtà un numero intero, 3 e poiché strcmp prevede una stringa, lo 3 verrà convertito in "3". Ma ciò dimostra che in questo caso potrebbe verificarsi una conversione, dal momento che strcmp è una funzione, mentre === è parte della lingua.

Quindi la mia preferenza in questo caso va a === (che è comunque più veloce di ==).

+0

Questa è la risposta più sensata I 'ho visto. Sono d'accordo che sia il tipo che il valore sono importanti per evitare problemi con il "cast helper". – Polynomial

+0

Nota che [hash_equals() dovrebbe essere usato] (http://stackoverflow.com/a/27066499/978756) quando si testano i valori hash prodotti con una funzione forte come 'password_hash'. – Polynomial

-3

Penso che usare == sia sufficiente nel tuo caso.

== controlli di uguaglianza indipendentemente dal tipo, mentre === controlli di uguaglianza e tipo.

1 == "1" = True

1 === "1" = False

Dato che non siamo troppo preoccupati con il tipo, mi piacerebbe fare cose semplici e andare con ==.

+1

Sono consapevole delle differenze tra '==' e '===', ma I ' Sto cercando di capire se c'è un caso specifico per la sicurezza che mi manca. Per esempio, c'è un motivo * non * per usare 'strcmp'? – Polynomial

+0

Dato che non si è interessati a un confronto di dati binari, non userei strcmp. Non ti preoccupi di quanto siano diverse le stringhe - ti preoccupi solo se sono semanticamente uguali o meno. –

+0

Cosa succede se 'bcrypt' non riesce per qualche motivo? Potrebbe essere possibile che un valore di ritorno non stringa sia considerato uguale a un valore stringa per '$ hash', dove quella variabile è un hash valido? – Polynomial

0

Che non è corretto, si prega di guardare la definizione della funzione. Secondo PHP:

Returns < 0 if str1 is less than str2;

> 0 if str1 is greater than str2,

and 0 if they are equal

Si restituisce meno di 0 se str1 è minore di str2. Nota la frase "minore di", non restituisce solo -1, ma qualsiasi valore negativo. Lo stesso accade quando str1 è maggiore di str2, ma restituisce un valore positivo, diverso da zero. Restituisce un valore positivo che può essere 1 o qualsiasi numero successivo.

strcmp() restituisce un numero che è la differenza tra le due stringhe che iniziano con l'ultimo carattere che è risultato essere simile.

Ecco un esempio:

$output = strcmp("red", "blue");

L'$ uscita variabile con contengono un valore di 16

6

Si deve usare le() funzione che è costruito in PHP hash_equals. Non ci sarebbe bisogno di fare la tua funzione. Hash_equals() restituirà un valore booleano.

A mio parere non è consigliabile utilizzare == o === per confrontare stringhe e stringhe con hash.

+1

Questa è ora la risposta corretta per i valori generati da 'password_hash', ma' hash_equals' non esisteva nel PHP tradizionale al momento della richiesta, e non si applica agli hash flat (che non dovrebbero comunque essere usati ma a volte sono richiesti per eredità) – Polynomial