2010-10-11 5 views
0

J'ai développé une classe de session PHP et l'ai testée en utilisant quelques exemples (voir le code source ci-dessous). Cela semble aller bien. Maintenant, je voudrais que cette session soit "sécurisée". J'ai trouvé un exemple de code qui est destiné à crypter un cookie (dans le livre de Courioso Expert PHP et MySQL). Voici cet extrait de code.Sécuriser les cookies dans les sessions PHP

Code pour cookie crypté

$cookieData = serialize($user); 

$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC); 
srand(); 
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND); 
$encryptedData = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $secret, 
      $cookieData, MCRYPT_MODE_CBC, $iv); 
setcookie('user', base64_encode).':'.$iv); 

et un code similaire pour déchiffrer le cookie

Ma première question est: puis-je faire confiance à ce code. C'est à dire. est-ce vraiment sécurisé? (J'ai essayé d'autres exemples de code de ce livre et les ai trouvés plutôt bogués).

Je ne comprends pas bien comment le code pour chiffrer un cookie pourrait être intégré dans ma classe de session (soit le code ci-dessus - ou tout autre code de chiffrement des cookies). Dois-je remplacer le cookie généré automatiquement par PHP (PHPSESSID) ou générer un nouveau cookie et chiffrer ce cookie personnalisé? (Ma conjecture est la seconde est vraie, mais je voudrais être sûr).

Comment la protection via des cookies cryptés est-elle destinée à fonctionner? J'imagine l'attaque suivante: (1) si l'attaquant obtient en quelque sorte le cookie dans sa main il répond simplement avec le même cookie. D'accord. il n'a pas le mot de passe mais il a le mot de passe crypté. Plus tard, je vérifie seulement si le mot de passe chiffré est correct. Donc, si l'attaquant a le cookie: game over - peu importe si le cookie contient le mot de passe ou "seulement" le mot de passe crypté. Correct? (2) D'accord, ce problème peut être résolu en utilisant une transmission chiffrée comme SSL. Mais alors je pense que si j'utilise SLL que la transmission est de toute façon chiffrée. Je n'ai pas besoin de chiffrer le mot de passe une seconde fois en utilisant la fonction de cryptage. Correct?

Voici le code de la classe de session que j'ai déjà.

Merci

<?php 

class SessionClass { 

    private static $_instance; 
    public static function getInstance() 
    { 
     if (!(self::$_instance instanceof self)) 
     { 
      self::$_instance = new self(); 
     } 
     return self::$_instance; 
    } // getInstance 


    public function __construct() 
    { 
     session_set_save_handler(
      array($this, "open"), array($this, "close"), 
      array($this, "read"), array($this, "write"), 
      array($this, "destroy"), array($this, "gc") 
     ); 

     $createTable = "CREATE TABLE IF NOT EXISTS `session`(". 
          "`sessionID` VARCHAR(128), ". 
          "`data` MEDIUMBLOB, ". 
          "`timestamp` INT, ". 
          "`ip` VARCHAR(15), ". 
          "PRIMARY KEY (`sessionID`), ". 
          "KEY (`timestamp`, `sessionID`))"; 

     mysql_query($createTable); 
    } // construct 


    public function __destruct() { 
     session_write_close(); 
    } 

    public function open ($path, $id) { 
     // do nothing 
     return (true); 
    } 

    public function close() { 
     // do nothing 
     return (true); 
    } 

    public function read($id) 
    { 
     $escapedID = mysql_escape_string($id); 
     $query = sprintf("SELECT * FROM session WHERE sessionID = '%s'", $escapedID); 
     $res = mysql_query($query); 

     if ((!$res) || (!mysql_num_rows($res))) { 
      $timestamp = time(); 
      $query = sprintf("INSERT INTO session (sessionID, timestamp) VALUES ('%s', %s)", $escapedID, $timestamp); 
      mysql_query($query); 
      return ''; 
     } elseif (($row = mysql_fetch_assoc($res))) { 
      $query = "UPDATE session SET timestamp = "; 
      $query .= time(); 
      $query .= sprintf (" WHERE sessionID = '%s'", $escapedID); 
      mysql_query($query); 
      return $row['data']; 
     } // elseif 

     return ""; 
    } // read 


    public function write($id, $data) 
    { 
     $query = "REPLACE INTO session (sessionID, data, ip, timestamp) "; 
     $query .= sprintf("VALUES ('%s', '%s', '%s', %s)", 
      mysql_escape_string($id), mysql_escape_string($data), 
      $_SERVER['REMOTE_ADDR'], time()); 
     mysql_query($query); 
     return (true); 
    } // write 


    public function destroy($id) 
    { 
     $escapedID = mysql_escape_string($id); 
     $query = sprintf("DELETE FROM session WHERE sessionID = %s", $escapedID); 
     $res = mysql_query($query); 
     return (mysql_affected_rows($res) == 1); 
    } // destroy 


    public function gc($lifetime) 
    { 
     $query = "DELETE FROM session WHERE "; 
     $query = sprintf("%s - timestamp > %s", time(), $lifetime); 
     mysql_query($query); 
     return (true); 
    } // gc 

} // SessionClass 
+0

Vous stockez le 'sessionID' dans la base de données cela peut être obtenu avec l'injection sql et utilisé pour vous connecter, ce qui annule le but du hachage d'un mot de passe. – rook

+0

L'adresse IP peut également changer pendant une session si elle se trouve derrière un équilibreur de charge. Tels que s'ils sont dans une école ou un grand réseau d'entreprise. – rook

Répondre

1

Si je me écarter de votre question initiale. Vous devez pas stocker les mots de passe dans un cookie. Un cookie est stocké sur le côté client. Quel que soit le cryptage, une option beaucoup plus sécurisée consisterait à enregistrer les détails de l'authentification de l'utilisateur dans une session et à stocker simplement un jeton sur le cookie côté client qui fera appel à la session concernée.

+0

D'accord qu'il devrait probablement mettre le mot de passe dans la session, mais ce n'est pas toujours une "option beaucoup plus sécurisée". Sur certaines configurations d'hôtes partagées, les informations de session sont lisibles pour tous les utilisateurs de la machine, par exemple. –

2

La raison de l'utilisation des sessions est de ne pas stocker les données sensibles du côté client mais de les conserver côté serveur. Et la seule connexion à ces données est l'identifiant de session qui devrait être changé périodiquement et avec chaque authentification et changement d'autorisation.

Si vous voulez maintenant stocker ces données sur le côté client (peu importe sous quelle forme ou représentation), vous faire le contraire de ce que les sessions sont destinées à être utilisées pour. Alors ne le faites pas et gardez vos données sensibles côté serveur.