2015-04-07 21 views
5

Ho cercato di trovare informazioni sul fatto che password_verify() utilizza il confronto di tempo costante di lunghezza per evitare attacchi di temporizzazione.PHP password_verify() e confronto lento a confronto

Ora, semplice esempio:

$hash = '$2y$10$HH3906lfby7HOy1N3duQh.Kju.84ct6AcMZm2p/SYZsZSXuYWvvT.'; 

$startTime = microtime(TRUE); 
password_verify('rasmuslerdorf', $hash); 
$endTime = microtime(TRUE); 

$time = $endTime - $startTime; 

Questo produce sempre uscita leggermente diverso, che, secondo this article ("Perché il codice hash in questa pagina confrontare gli hash in 'tempo di lunghezza costante'? "Paragrafo), potrebbe essere utilizzato in attacco di temporizzazione per raccogliere un hash. Penso che questi risultati siano piuttosto casuali, ma sicuramente non costanti.

La domanda è, password_verify() utilizza il confronto di tempo costante di lunghezza per evitare l'attacco di temporizzazione? Non ci sono informazioni su di esso nei documenti e, a causa della mia esperienza superficiale, non riesco a interpretare bene i tempi di elaborazione delle funzioni.

risposta

8

La risposta è Sì, utilizza un confronto temporale a lunghezza costante.

Questo è un estratto della funzione password_verify php

/* We're using this method instead of == in order to provide 
* resistance towards timing attacks. This is a constant time 
* equality check that will always check every byte of both 
* values. */ 
for (i = 0; i < hash_len; i++) { 
    status |= (ret->val[i]^hash[i]); 
} 

Si può dare un'occhiata al codice sorgente completo https://github.com/php/php-src/blob/master/ext/standard/password.c

+0

Grazie! Non ho mai visto questo repo prima. – Nevertheless

4

Risposta breve: sì, lo fa.

Risposta lunga: non è necessario.

Per comprendere il motivo per cui non è necessario, abbiamo bisogno di guardare le stringhe confrontate:

$2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S 
$2y$10$ILlWQrYyDJvHHkxcCgjm7OThLRAmMcTzsJOZOwjaSYiRUHq8LVYde 
$2y$10$8JfydDKUNbOeiybwZ9m.j.5TC8CBqkc3RZu2DX42A4dFNpNYPWfzm 
$2y$10$qeG.53lr9PVVGN4Yk.kSZuOMpfone5kINyWVpAf2gUXPseU2WdSzK 
$2y$10$nZUgPUwiXIvCJ9BY1wbtbuV5vH6yff9CNyumFsI/NN2eJmf20iec. 

Ecco 5 diverse hash della stessa password. Il formato è:

$2y$10$saltsaltsaltsaltsaltsahashhashhashhashhashhashhashhas 

Ora, ad un attaccante remoto (quello che sarebbe stato in esecuzione attacchi di temporizzazione), il sale è un segreto. E il sale è lo stesso quando ci riproviamo. Per esempio:

stored password "test": 
hash = $2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S 

Se l'attaccante tenta la password "abc", internamente password_verify() chiamerà crypt("abc", hash). Che si tradurrà in:

$2y$10$9JxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim 

Ora, diamo un'occhiata a quei due hash, fianco a fianco:

$2y$10$9JxHB8U1QKsLS/ynplKzm.iIO7f6gtTKYA61ppVuANYxWNCA5DW1S 
$2y$10$9JxHB8U1QKsLS/ynplKzm.FTYpGS/gNDw4SB6YD0wEtCSPgGvtPim 

Avviso il sale è la stessa? Si noti che tutto fino al primo . è lo stesso. Si noti inoltre che l'attaccante non ha idea di cosa sia il sale.

Se l'utente malintenzionato era in grado di attaccare il paragone, non avrebbe funzionato. Perché non conoscono il sale (e quindi deducendo ciò che l'hash è semplicemente sprecato tempo poiché senza il sale non possono determinare la password).

Quindi la sicurezza dei tempi non è strettamente necessaria.

Perché è incluso quindi? Perché tutti fanno errori. Perché la difesa in profondità è una buona idea.Perché questa analisi presuppone che nulla dell'hash sia utile senza il sale (es: cosa succede se un difetto in bcrypt ha polarizzato gli hash in base alla password, quindi senza sapere il sale lo spazio delle chiavi viene ridotto da 72^255).

In breve, è una buona cosa avere, ma non è strettamente necessario ...