Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 /// zend/Auth/Adapter/Digest.php class Zend_Auth_Adapter_Digest implements Zend_Auth_Adapter_Interface { .... .... while ($line = trim(fgets($fileHandle))) { if (substr($line, 0, $idLength) === $id) { if ($this->_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))) { $result['code'] = Zend_Auth_Result::SUCCESS; } else { $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; $result['messages'][] = 'Password incorrect'; } return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); } } $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found"; return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); } /** * Securely compare two strings for equality while avoided C level memcmp() * optimisations capable of leaking timing information useful to an attacker * attempting to iteratively guess the unknown string (e.g. password) being * compared against. * * @param string $a * @param string $b * @return bool */ protected function _secureStringCompare($a, $b) { if (strlen($a) !== strlen($b)) { return false; } $result = 0; for ($i = 0; $i < strlen($a); $i++) { $result |= ord($a[$i]) ^ ord($b[$i]); } return $result == 0; }
Cette classe retourne false même si l'authentification est juste.
Mon fichier text est: ../public/digest/auth.txt ,son contenu est:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 Kotama:localhost:721a9b52bfceacc503c056e3b9b93cfa username: Kotama realm: localhost passeword: 721a9b52bfceacc503c056e3b9b93cfa ; ou md5(coucou) $file='../public/digest/auth.txt'; $realm='localhost'; $login='Kotama'; $passe='coucou'; $adaptateur = new Zend_Auth_Adapter_Digest($file,$realm,$login,$passe); $this->result = $adaptateur->authenticate(); print_r($this->result); Zend_Auth_Result Object ( [_code:protected] => -3 [_identity:protected] => Array ( [realm] => localhost [username] => Kotama ) [_messages:protected] => Array ( [0] => Password incorrect ) )
Quand j'ai vérifié la classe en question, j'ai observé que la fonctionqui compare les codes ASCII des deux chaînes $a et $b bit par bit, elle retourne false parce quelle compare deux chaîne différentes:Code:_secureStringCompare($a, $b)
$a c'est le mot de passe en md5 dans mon fichier auth.txtCode:_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))
$b c'est le contenu de toute la ligne dans mon fichier auth.txt
ou:Code:
1
2 $a=substr($line, -32) $b=md5("$this->_username:$this->_realm:$this->_password")
Quand j'ai changé les paramètres passés à cette fonction comme suit:Code:$b=md5(Kotama:localhost:721a9b52bfceacc503c056e3b9b93cfa)
tel que :Code:_secureStringCompare(substr($line, -32), md5("$this->_password"))
le mot de passe d'authentification.Code:
1
2 substr($line, -32) la chaîne qui se trouve à la fin de la ligne dans le fichier auth.txt md5("$this->_password"))
l'authentification est faite avec succès, résultat affiché est:
la classe Zend/Auth/Adapter/Digest.php après le changement:Code:Zend_Auth_Result Object ( [_code:protected] => 1 [_identity:protected] => Array ( [realm] => localhost [username] => Kotama ) [_messages:protected] => Array ( ) )
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 class Zend_Auth_Adapter_Digest implements Zend_Auth_Adapter_Interface { .... .... while ($line = trim(fgets($fileHandle))) { if (substr($line, 0, $idLength) === $id) { // j'ai changé md5("$this->_username:$this->_realm:$this->_password") par md5("$this->_password") if ($this->_secureStringCompare(substr($line, -32), md5("$this->_password"))) { $result['code'] = Zend_Auth_Result::SUCCESS; } else { $result['code'] = Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID; $result['messages'][] = 'Password incorrect'; } return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); } } $result['code'] = Zend_Auth_Result::FAILURE_IDENTITY_NOT_FOUND; $result['messages'][] = "Username '$this->_username' and realm '$this->_realm' combination not found"; return new Zend_Auth_Result($result['code'], $result['identity'], $result['messages']); }
Citation:
/**
* Securely compare two strings for equality while avoided C level memcmp()
* optimisations capable of leaking timing information useful to an attacker
* attempting to iteratively guess the unknown string (e.g. password) being
* compared against.
*
* @param string $a
* @param string $b
* @return bool
*/
Est ce qu'il y a une autre solution sans touché au contenu de la classe prédéfinie?Code:
1
2
3
4
5
6
7
8
9
10
11
12
13 protected function _secureStringCompare($a, $b) { if (strlen($a) !== strlen($b)) { return false; } $result = 0; for ($i = 0; $i < strlen($a); $i++) { $result |= ord($a[$i]) ^ ord($b[$i]); } return $result == 0; } }