vendredi, 19 janvier 2007

De la sécurité des sessions PHP

Dans la majorité des espaces requierant une authentification sur un site web, le soin du suivi de l'utilisateur est laissé aux sessions, ces petits cookies qui viennent se placer chez le client afin de permettre à l'application web de le reconnaitre lors du passage à la page suivante.

Ce modèle de sécurité a du être imaginé à cause de la nature "connexionless" du protocole HTTP, c'est-à-dire la fermeture de la connexion TCP au serveur entre 2 chargements de page consécutifs (contrairement aux modèles de connexions "continues").

Malheureusement différentes techniques pour voler ces informations de sessions existent, elles se nomment credential token stealing, et sont souvent réalisables grâce à des failles de type XSS.

Cet article va expliquer quel est le point faible des sessions, ainsi que présenter une solution pour en améliorer la sécurité. Un exemple d'implémentation sera une fois de plus donné en PHP.

Problèmes des sessions

Le problème lié aux sessions est que l'identité de l'utilisateur, une fois identifiée, repose entièrement sur ce cookie. Si une personne malveillante parvient à obtenir la valeur du cookie, elle pourra alors se faire passer pour la personne légitime aux yeux de l'application.

Meilleure emprunte (fingerprint)

Une première amélioration est d'associer la valeur du cookie à d'autres éléments qu'une personne malveillante ne peut pas modifier : l'ip de connexion, la signature du navigateur, etc...
Tous ces éléments combinés ensemble donnent ce qu'on appelle l'emprunte de la session, et tous ces éléments sont nécessaires pour pouvoir usurper une identité. La principale difficulté est l'adresse ip de connexion, mais si la personne malveillante est sur le même sous-réseau que la personne légitime, l'adresse ip n'est plus un problème. Autre désavantage d'un fingerprinting étendu, si la personne légitime est sur une connexion à adresse ip dynamique, elle devra se réauthentifier à chaque changement d'adresse ip.

ID de session temporaire

Une autre amélioration est la regénération dynamique de la valeur du cookie. A chaque nouvelle connexion, on test si l'utilisateur est légitime, et on génère une nouvelle valeur qu'on lui envoie.
Si une personne malveillante arrive à voler un cookie, sa valeur ne sera que temporaire et dès le prochain chargement de page, la valeur volée devient obsolète.
Mais cela est aussi vrai à l'inverse, si la personne malveillante arrive à usurper l'identité avant que la personne légitime ne redemande une page, c'est la personne légitime qui sera déconnectée du site.

Implémentation en PHP

Une combinaison des 2 méthodes améliorera la sécurité des sessions, sans pour autant la rendre infaillible.

Voici une petite implémentation en PHP :

<?php
/*
* Inspirated from SecureSession class
* initially written by Vagharshak Tozalakyan <vagh@armdex.com>
*/
class SecureSession {

private $_check_browser;
private $_check_ip_blocks = 0;
private $_padding = '*ftt56+g zwc%&gh7/3-lf%254*6c_qm';
private $_regenerate_id = true;
private $_session_var_name = __CLASS__;

public function _construct($check_browser = true,
$check_ip_block = 0, $regenerate_id = true)
{
$this->_check_browser = $check_browser;
$this->_check_ip_block = $check_ip_block;
$this->_regenerate_id = $regenerate_id;

$_SESSION[$this->_session_var_name] = $this->_fingerprint();
$this->_regenerateId();
}

public function isValid()
{
$this->_regenerateId();
return (isset($_SESSION[$this->_session_var_name])
&& $_SESSION[$this->_session_var_name] == $this->_fingerprint());
}

private function _fingerprint()
{
$fingerprint = "";
if ($this->_check_browser) {
$fingerprint .= $_SERVER['HTTP_USER_AGENT'];
}
if ($this->_check_ip_blocks) {
$num_blocks = min(abs(intval($this->check_ip_blocks)), 4);
$blocks = explode('.', $_SERVER['REMOTE_ADDR']);
for ($i=0; $i<$num_blocks; $i++) {
$fingerprint .= $blocks[$i] . '.';
}
}
return sha1($fingerprint . $this->_padding);
}

private function _regenerateId()
{
if ($this->_regenerate_id && function_exists('session_regenerate_id')) {
session_regenerate_id(true);
}
}
}

?>

1 commentaire:

Anonyme a dit…

salut svp j'ai pas bien compris cette classe est je veut l'intégrer avec ma base de donne qui sur localhost et je ne sais pas comment faire si veut pouvez m'aide n'hésiter pas voila mon email
rboussine@gmail.com