sept 09
Sécuriser une session PHP

En fait cet article aurait dû s’appeler : sécuriser une session à la façon d’un gros parano. Mais bon, c’est une petite classe très simple d’utilisation et bien pratique, surtout si votre site est hébergé sur un mutualisé où n’importe lequel de vos collocataires peut espionner et modifier vos fichiers de sessions.
Il s’agit donc d’une classe qui va se substituer à la fonction « session_start() » de PHP. Par la suite il n’y a absolument rien à changer dans votre code. Juste remplacer les « session_start() » par des « $sess = new Session(); » et vos sessions sont dignes de la NSA !
Que fait exactement cette classe ?
Cette classe permet deux choses :
- Signer la session en fonction de son contenu, d’une clef secrète et de variables qui identifient l’utilisateur (identifiant de session, adresse IP et useragent). Ceci permet d’éviter ce qu’on appelle le « Session Hijacking » ou le fait qu’en récupérant l’identifiant de session de quelqu’un d’autre on puisse se faire passer pour lui.
Dans le cas où la signature ne correspond pas au contenu de la session, celle-ci est donc détruite (contenu et identifiant). - Chiffrer le contenu de la session si vous le souhaitez (il suffit alors d’initier la session avec « $sess = new Session(true); »). Dans ce cas de figure, avant d’être signée la session est encryptée à l’aide d’un algo RIJNDAEL_256, et sera automatiquement décryptée à la réception !
Les variables de session utilisées sont totalement invisibles, vous pouvez faire un « print_r($_SESSION); » pour le vérifier, car elles sont automatiquement supprimées à l’initialisation de la classe, et recréées juste avant sa fermeture. Pas non plus de conflit possible avec vos autres variables de session, c’est vraiment tranquille !
Pour personnaliser la clef utilisée pour l’encryption et la signature, vous êtes invités à definir une constante SESSION_SECRET avant d’appeler la session.
Enfin, pour savoir si la session est passée correctement ou si elle a été réinitialisée vous pouvez regarder la valeur de « $sess->valid » (true si tout va bien, false sinon).
Voilà donc le code source de cette fabuleuse classe :
class Session {
public $valid = true;
protected $secret = null;
protected $encrypt = null;
function __construct($encrypt=false) {
$this->secret = defined(‘SESSION_SECRET’) ? SESSION_SECRET : »;
$this->secret .= session_id() . $_SERVER[‘REMOTE_ADDR’] . $_SERVER[‘HTTP_USER_AGENT’];
$this->encrypt = $encrypt;
session_start();
$this->valid = $this->check();
}
function __destruct() {
$this->lock();
}
protected function lock() {
$_SESSION = array(‘dat’=>$this->session_values());
$_SESSION[‘chk’] = $this->hash($_SESSION[‘dat’]);
}
protected function session_values() {
$sess = serialize($_SESSION);
if ($this->encrypt) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);
$sess = mcrypt_encrypt(MCRYPT_RIJNDAEL_256,sha1($this->secret,true),$sess,MCRYPT_MODE_ECB,$iv);
}
return $sess;
}
protected function check() {
if (!@count($_SESSION)) return true;
if ($_SESSION[‘chk’] == $this->hash($_SESSION[‘dat’])) {
if ($this->encrypt) {
$iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256,MCRYPT_MODE_ECB);
$iv = mcrypt_create_iv($iv_size,MCRYPT_RAND);
$_SESSION[‘dat’] = mcrypt_decrypt(MCRYPT_RIJNDAEL_256,sha1($this->secret,true),$_SESSION[‘dat’],MCRYPT_MODE_ECB,$iv);
}
$_SESSION = unserialize($_SESSION[‘dat’]);
return true;
}
session_destroy();
session_start();
session_regenerate_id(true);
return false;
}
protected function hash($s) {
return sha1($this->secret . $s,false);
}
}
?>
Edit : pour un exemple en live avec le source : clic !.
