135 votes

Quel est le meilleur moyen d'empêcher le détournement de session ?

Cela concerne plus particulièrement l'utilisation d'un cookie de session client pour identifier une session sur le serveur.

La meilleure solution consiste-t-elle à utiliser le cryptage SSL/HTTPS pour l'ensemble du site web, ce qui vous donne la meilleure garantie qu'aucune attaque de type "man in the middle" ne sera en mesure de renifler un cookie de session client existant ?

Et peut-être la deuxième meilleure solution est-elle d'utiliser une sorte de cryptage de la valeur de session elle-même qui est stockée dans votre cookie de session ?

Si un utilisateur malveillant a un accès physique à une machine, il peut toujours consulter le système de fichiers pour récupérer un cookie de session valide et l'utiliser pour détourner une session ?

146voto

Josh Hinman Points 4064

Le cryptage de la valeur de la session n'aura aucun effet. Le cookie de session est déjà une valeur arbitraire, le crypter ne fera que générer une autre valeur arbitraire qui peut être reniflée.

La seule véritable solution est le HTTPS. Si vous ne souhaitez pas appliquer le protocole SSL à l'ensemble de votre site (peut-être pour des raisons de performances), vous pouvez peut-être vous contenter de protéger les zones sensibles par SSL. Pour ce faire, assurez-vous d'abord que votre page de connexion est HTTPS. Lorsqu'un utilisateur se connecte, définissez un cookie sécurisé (c'est-à-dire que le navigateur ne le transmettra que par un lien SSL) en plus du cookie de session ordinaire. Ensuite, lorsqu'un utilisateur visite l'une de vos zones "sensibles", redirigez-le vers HTTPS et vérifiez la présence de ce cookie sécurisé. Un véritable utilisateur l'aura, un pirate de session ne l'aura pas.

EDIT : Cette réponse a été initialement écrite en 2008. Nous sommes en 2016 maintenant, et il n'y a aucune raison de ne pas avoir SSL sur l'ensemble de votre site. Fini le HTTP en texte clair !

31 votes

HTTPS empêchera seulement le reniflage. Mais si vous avez un XSS, ou si les ID de session peuvent être devinés facilement, ou si vous êtes vulnérable à la fixation de session, ou si votre stockage d'ID de session est faible (injection SQL ?), SSL ne sera d'aucune utilité.

5 votes

@Josh Si un utilisateur malveillant a un accès physique à une machine, il peut toujours regarder le système de fichiers pour récupérer un cookie de session valide et l'utiliser pour détourner une session ?

77 votes

Si un utilisateur malveillant a un accès physique à un système de fichiers, il n'a pas besoin de détourner une session.

44voto

Le SSL n'aide que pour les attaques par reniflage. Si un attaquant a accès à votre machine, je suppose qu'il peut également copier votre cookie sécurisé.

Au minimum, faites en sorte que les vieux cookies perdent leur valeur au bout d'un certain temps. Même une attaque de détournement réussie sera contrecarrée lorsque le cookie cessera de fonctionner. Si l'utilisateur possède un cookie provenant d'une session qui s'est connectée il y a plus d'un mois, obligez-le à saisir à nouveau son mot de passe. Assurez-vous qu'à chaque fois qu'un utilisateur clique sur le lien "déconnexion" de votre site, l'ancien UUID de la session ne pourra plus jamais être utilisé.

Je ne suis pas sûr que cette idée fonctionne mais c'est parti : Ajoutez un numéro de série dans votre cookie de session, peut-être une chaîne comme celle-ci :

SessionUUID, Numéro de série, Date/heure actuelle

Cryptez cette chaîne et utilisez-la comme cookie de session. Changez régulièrement le numéro de série - peut-être lorsque le cookie a 5 minutes, puis rééditez le cookie. Vous pouvez même le réémettre à chaque consultation de page si vous le souhaitez. Du côté du serveur, gardez un enregistrement du dernier numéro de série que vous avez émis pour cette session. Si quelqu'un envoie un cookie avec un numéro de série erroné, cela signifie qu'un attaquant utilise peut-être un cookie qu'il a intercepté auparavant. Invalidez donc l'UUID de la session et demandez à l'utilisateur de saisir à nouveau son mot de passe, puis rééditez un nouveau cookie.

N'oubliez pas que votre utilisateur peut avoir plus d'un ordinateur et qu'il peut donc avoir plus d'une session active. Ne faites pas quelque chose qui les oblige à se reconnecter chaque fois qu'ils changent d'ordinateur.

0 votes

Je sais que c'est un vieux message, mais je voulais juste ajouter que si un attaquant devait détourner la session dans la fenêtre allouée par le "numéro de série", cela ne l'affecterait pas.

0 votes

@crush, mais alors l'attaquant serait bloqué après la fenêtre allouée, non ? Donc, au moins, la fenêtre d'attaque est petite (er).

3 votes

Le seul problème est que si l'utilisateur quitte votre site web pendant 5 minutes, il devra se reconnecter.

21voto

Nathan Points 109

Avez-vous envisagé de lire un livre sur la sécurité de PHP ? Hautement recommandé.

J'ai eu beaucoup de succès avec la méthode suivante pour les sites non certifiés SSL.

  1. Interdisez les sessions multiples sous le même compte, en vous assurant que vous ne vérifiez pas uniquement l'adresse IP. Vérifiez plutôt le jeton généré lors de la connexion, qui est stocké avec la session de l'utilisateur dans la base de données, ainsi que l'adresse IP, HTTP_USER_AGENT, etc.

  2. Utilisation des hyperliens basés sur les relations Génère un lien ( ex. http://example.com/secure.php?token=2349df98sdf98a9asdf8fas98df8 ) Le lien est accompagné d'une chaîne MD5 salée aléatoire x-BYTE (taille préférée). Lors de la redirection de la page, le jeton généré aléatoirement correspond à une page demandée.

    • Lors du rechargement, plusieurs contrôles sont effectués.
    • Adresse IP d'origine
    • HTTP_USER_AGENT
    • Jeton de session
    • vous comprenez.
  3. Cookie d'authentification de session à courte durée de vie. Comme indiqué ci-dessus, un cookie contenant une chaîne sécurisée, qui est l'une des références directes à la validité de la session, est une bonne idée. Faites en sorte qu'il expire toutes les x minutes, en réémettant ce jeton, et en resynchronisant la session avec les nouvelles données. Si les données ne correspondent pas, il faut soit déconnecter l'utilisateur, soit lui demander de réauthentifier sa session.

Je ne suis en aucun cas un expert en la matière, mais j'ai un peu d'expérience dans ce domaine particulier. J'espère que ces informations seront utiles à tous.

4 votes

Y a-t-il des livres que vous recommanderiez ?

1 votes

D'autant plus que l'OP n'a rien dit sur PHP en particulier, je dirais qu'il est préférable de regarder juste un livre général sur la sécurité (d'autant plus que la sécurité entre les différents langages ne diffère que dans les détails d'implémentation, mais les concepts restent les mêmes).

1 votes

En 2017, même facebook/gmail etc permet des sessions multiples sous le même compte (surtout avec les appareils mobiles) à moins de détester vos utilisateurs, le #1 est un peu dépassé.

21voto

theironyis Points 81
// Collect this information on every request
$aip = $_SERVER['REMOTE_ADDR'];
$bip = $_SERVER['HTTP_X_FORWARDED_FOR'];
$agent = $_SERVER['HTTP_USER_AGENT'];
session_start();

// Do this each time the user successfully logs in.
$_SESSION['ident'] = hash("sha256", $aip . $bip . $agent);

// Do this every time the client makes a request to the server, after authenticating
$ident = hash("sha256", $aip . $bip . $agent);
if ($ident != $_SESSION['ident'])
{
    end_session();
    header("Location: login.php");
    // add some fancy pants GET/POST var headers for login.php, that lets you
    // know in the login page to notify the user of why they're being challenged
    // for login again, etc.
}

Il s'agit de capturer des informations "contextuelles" sur la session de l'utilisateur, des éléments d'information qui ne devraient pas changer au cours d'une seule session. Un utilisateur ne va pas se trouver en même temps sur un ordinateur aux États-Unis et en Chine, n'est-ce pas ? Donc, si l'adresse IP change soudainement au cours de la même session, cela implique fortement une tentative de détournement de session. Vous sécurisez donc la session en y mettant fin et en obligeant l'utilisateur à se réauthentifier. Cela déjoue la tentative de piratage, l'attaquant est également obligé de se connecter au lieu d'avoir accès à la session. Notifiez l'utilisateur de la tentative (en l'ajaxant un peu), et vola, l'utilisateur légèrement ennuyé+informé et sa session/information est protégée.

Nous ajoutons User Agent et X-FORWARDED-FOR pour faire de notre mieux pour capturer l'unicité d'une session pour les systèmes derrière des proxies/réseaux. Il se peut que vous puissiez utiliser plus d'informations que cela, n'hésitez pas à faire preuve de créativité.

Ce n'est pas à 100%, mais c'est sacrément efficace.

Vous pouvez faire plus pour protéger les sessions, les faire expirer, lorsqu'un utilisateur quitte un site web et revient, l'obliger à se connecter à nouveau. Vous pouvez détecter le départ et le retour d'un utilisateur en capturant un HTTP_REFERER vide (le domaine a été tapé dans la barre d'URL), ou vérifier si la valeur du HTTP_REFERER correspond à votre domaine ou non (l'utilisateur a cliqué sur un lien externe/créé pour arriver sur votre site).

Faites expirer les sessions, ne les laissez pas rester valides indéfiniment.

Ne vous fiez pas aux cookies, ils peuvent être volés, c'est l'un des vecteurs d'attaque pour le détournement de session.

3 votes

J'ai déjà rencontré une situation où un certain FAI (assez important, mais techniquement arriéré) changeait de temps en temps l'IP du navigateur de l'utilisateur en fonction du reroutage des connexions de ses utilisateurs. La vérification de REMOTE_ADDR nous renvoyait alors des faux négatifs.

0 votes

Pourquoi prendre la peine de créer un hash ? $_SESSION['ident'] = $aip . $bip . $agent; serait tout aussi sûr.

4 votes

Si des utilisateurs mobiles utilisent votre site Web en déplacement et se déplacent d'un point d'accès à l'autre, leurs adresses IP changeront constamment et ils seront déconnectés de leur compte.

12voto

Alexandru Points 53

Il n'existe aucun moyen d'empêcher à 100% le détournement de session, mais certaines approches permettent de réduire le temps nécessaire à un attaquant pour détourner la session.

Méthode pour empêcher le détournement de session :

1 - toujours utiliser une session avec un certificat ssl ;

2 - envoyer le cookie de session uniquement avec httponly réglé sur true (empêcher javascript d'accéder au cookie de session)

2 - utilisez l'id de régénération de session à la connexion et à la déconnexion (note : n'utilisez pas la régénération de session à chaque requête car si vous avez des requêtes ajax consécutives, vous avez une chance de créer plusieurs sessions).

3 - définir un délai d'attente pour la session

4 - stocker l'agent utilisateur du navigateur dans une variable $_SESSION et comparer avec $_SERVER['HTTP_USER_AGENT'] à chaque requête

5 - Définissez un cookie symbolique et fixez le temps d'expiration de ce cookie à 0 (jusqu'à ce que le navigateur soit fermé). Régénérez la valeur du cookie pour chaque requête (pour les requêtes ajax, ne régénérez pas le cookie à jeton). EX :

    //set a token cookie if one not exist
    if(!isset($_COOKIE['user_token'])){
                    //generate a random string for cookie value
        $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

        //set a session variable with that random string
        $_SESSION['user_token'] = $cookie_token;
        //set cookie with rand value
        setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
    }

    //set a sesison variable with request of www.example.com
    if(!isset($_SESSION['request'])){
        $_SESSION['request'] = -1;
    }
    //increment $_SESSION['request'] with 1 for each request at www.example.com
    $_SESSION['request']++;

    //verify if $_SESSION['user_token'] it's equal with $_COOKIE['user_token'] only for $_SESSION['request'] > 0
    if($_SESSION['request'] > 0){

        // if it's equal then regenerete value of token cookie if not then destroy_session
        if($_SESSION['user_token'] === $_COOKIE['user_token']){
            $cookie_token = bin2hex(mcrypt_create_iv('16' , MCRYPT_DEV_URANDOM));

            $_SESSION['user_token'] = $cookie_token;

            setcookie('user_token', $cookie_token , 0 , '/' , 'donategame.com' , true , true);
        }else{
            //code for session_destroy
        }

    }

            //prevent session hijaking with browser user agent
    if(!isset($_SESSION['user_agent'])){
        $_SESSION['user_agent'] = $_SERVER['HTTP_USER_AGENT'];
    }

    if($_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT']){
      die('session hijaking - user agent');
    }

note : ne pas régénérer le cookie token avec une requête ajax note : le code ci-dessus est un exemple. note : si les utilisateurs se déconnectent, le cookie token doit être détruit ainsi que la session.

6 - ce n'est pas une bonne approche d'utiliser l'ip de l'utilisateur pour empêcher le détournement de session parce que l'ip de certains utilisateurs change à chaque demande. QUI AFFECTENT LES UTILISATEURS VALIDES

7 - Personnellement, je stocke les données de session dans la base de données, mais c'est à vous de choisir la méthode que vous adopterez.

Si vous trouvez une erreur dans mon approche, veuillez me corriger. Si vous avez d'autres moyens d'empêcher l'hyjaking de session, dites-le moi.

0 votes

Bonjour, j'essaie d'empêcher le détournement de session (en ASP.NET) et j'ai considéré toutes les étapes que vous avez suggérées. Cela fonctionne approximativement mais lorsque j'utilise le mode InPrivateBrowsing/incognito du navigateur, la session est détournée. Pouvez-vous me suggérer des éléments supplémentaires à ajouter dans la chaîne sessionId ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X