Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 : Sélectionner tout - Visualiser dans une fenêtre à part
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
Code : Sélectionner tout - Visualiser dans une fenêtre à part
_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:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
_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


Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
$a=substr($line, -32)
$b=md5("$this->_username:$this->_realm:$this->_password")
ou:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
$b=md5(Kotama:localhost:721a9b52bfceacc503c056e3b9b93cfa)
Quand j'ai changé les paramètres passés à cette fonction comme suit:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
_secureStringCompare(substr($line, -32), md5("$this->_password"))
tel que :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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:

Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
*/
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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?