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:
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 fonction
_secureStringCompare($a, $b)
qui 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:
_secureStringCompare(substr($line, -32), md5("$this->_username:$this->_realm:$this->_password"))
$a c'est le mot de passe en md5 dans mon fichier auth.txt
$b c'est le contenu de toute la ligne dans mon fichier auth.txt
1 2
| $a=substr($line, -32)
$b=md5("$this->_username:$this->_realm:$this->_password") |
ou:
$b=md5(Kotama:localhost:721a9b52bfceacc503c056e3b9b93cfa)
Quand j'ai changé les paramètres passés à cette fonction comme suit:
_secureStringCompare(substr($line, -32), md5("$this->_password"))
tel que :
1 2
| substr($line, -32) la chaîne qui se trouve à la fin de la ligne dans le fichier auth.txt
md5("$this->_password")) |
le mot de passe d'authentification.
l'authentification est faite avec succès, résultat affiché est:
Zend_Auth_Result Object ( [_code:protected] => 1 [_identity:protected] => Array ( [realm] => localhost [username] => Kotama ) [_messages:protected] => Array ( ) )
la classe Zend/Auth/Adapter/Digest.php après le changement:
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']);
} |
/**
* 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
*/
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;
}
} |
Est ce qu'il y a une autre solution sans touché au contenu de la classe prédéfinie?
Partager