Quelle est la meilleure façon d'éviter le détournement de session?

124

Plus précisément, cela concerne l'utilisation d'un cookie de session client pour identifier une session sur le serveur.

La meilleure réponse est-elle d'utiliser le cryptage SSL / HTTPS pour l'ensemble du site Web, et vous avez la meilleure garantie qu'aucun homme du milieu n'attaque ne pourra renifler un cookie de session client existant?

Et peut-être le deuxième meilleur pour utiliser une sorte de cryptage sur 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?

Adam
la source

Réponses:

140

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

La seule vraie solution est HTTPS. Si vous ne souhaitez pas utiliser SSL sur l'ensemble de votre site (peut-être avez-vous des problèmes de performances), vous pourrez peut-être vous en sortir avec uniquement SSL protégeant les zones sensibles. 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é (ce qui signifie que le navigateur ne le transmettra que via un lien SSL) en plus du cookie de session normal. 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 vrai utilisateur l'aura, pas un pirate de l'air de session.

EDIT : Cette réponse a été écrite à l'origine 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 clair!

Josh Hinman
la source
28
HTTPS empêchera le reniflement uniquement. 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 pas du tout amélioré.
Calimo
5
@Josh 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?
Pacerier le
72
Si un utilisateur malveillant a un accès physique à un système de fichiers, il n'a pas besoin de détourner une session.
Josh Hinman
25
@Josh. Ce n'est pas vrai, parfois un utilisateur a un accès physique limité dans le temps à un système de fichiers. Imaginez un ordinateur portable laissé déverrouillé par un collègue se précipitant vers les toilettes, maintenant tout ce que j'ai à faire est d'aller sur cet ordinateur portable, d'installer le plugin EditThisCookie, de récupérer ses cookies sur plus.google.com en utilisant la fonction d'exportation EditThisCookie et maintenant j'ai son compte . Temps pris: 18 secondes.
Pacerier
1
Je suis à peu près sûr que Google aura une sorte de fonctionnalité de sécurité intégrée, car c'est évidemment la première chose à laquelle vous penseriez lorsque vous parlez de détournement de session
xorinzor
42

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

À tout le moins, assurez-vous que les anciens cookies perdent leur valeur après un certain temps. Même une attaque de détournement réussie sera contrecarrée lorsque le cookie cessera de fonctionner. Si l'utilisateur a un cookie d'une session qui s'est connectée il y a plus d'un mois, faites-lui entrer à nouveau son mot de passe. Assurez-vous que chaque fois qu'un utilisateur clique sur le lien "déconnexion" de votre site, l'ancien UUID de session ne pourra plus jamais être utilisé.

Je ne sais pas si cette idée fonctionnera, mais voici: 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éémettez le cookie. Vous pouvez même le rééditer sur chaque page vue si vous le souhaitez. Du côté du serveur, gardez une trace du dernier numéro de série que vous avez émis pour cette session. Si quelqu'un envoie un cookie avec le mauvais numéro de série, cela signifie qu'un attaquant peut utiliser un cookie qu'il a intercepté plus tôt, invalidez donc l'UUID de session et demandez à l'utilisateur de saisir à nouveau son mot de passe, puis de réémettre 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 rien qui les oblige à se reconnecter chaque fois qu'ils basculent entre les ordinateurs.


la source
Je sais que c'est un ancien message, mais je voulais juste inclure que si un attaquant détournait la session dans la fenêtre attribuée par le "numéro de série", cela ne l'affecterait pas.
écraser le
@crush, mais l'attaquant serait verrouillé après la fenêtre allouée, non? Donc, à tout le moins, la fenêtre d'attaque est petite (euh).
Johanneke
2
Le seul problème est que si l'utilisateur quitte votre site Web pendant 5 minutes, il devra se reconnecter
elipoultorak
21

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

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

  1. Désactivez plusieurs sessions sous le même compte, en vous assurant de ne pas vérifier cela uniquement par adresse IP. Vérifiez plutôt par jeton généré lors de la connexion qui est stocké avec la session des utilisateurs dans la base de données, ainsi que l'adresse IP, HTTP_USER_AGENT et ainsi de suite

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

    • Lors du rechargement, plusieurs vérifications sont effectuées.
    • Adresse IP d'origine
    • HTTP_USER_AGENT
    • Jeton de session
    • tu obtiens le point.
  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é des sessions, est une bonne idée. Faites-le expirer toutes les x minutes, réémettez ce jeton et resynchronisez la session avec les nouvelles données. En cas de correspondance erronée dans les données, déconnectez l'utilisateur ou demandez-lui de ré-authentifier sa session.

Je ne suis en aucun cas un expert sur le sujet, j'ai eu un peu d'expérience dans ce sujet particulier, j'espère que cela aidera tout le monde.

Nathan
la source
4
Y a-t-il des livres que vous recommanderiez?
Rikki
1
Surtout étant donné que l'OP n'a rien dit sur PHP spécifiquement, je dirais qu'il vaut mieux ne regarder qu'un livre de sécurité général (d'autant plus que la sécurité entre les différentes langues ne diffère que dans les détails de mise en œuvre, mais les concepts restent les mêmes).
matts1
en 2017, même facebook / gmail etc. autorise plusieurs sessions sous le même compte (en particulier avec les appareils mobiles) sauf si vous détestez vos utilisateurs, le n ° 1 est un peu dépassé.
cowbert
20
// 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.
}

Cela permet de capturer des informations «contextuelles» sur la session de l'utilisateur, des informations qui ne devraient pas changer au cours de la vie d'une seule session. Un utilisateur ne sera pas à la fois devant 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 piratage de session, vous sécurisez la session en mettant fin à la session et en forçant l'utilisateur à s'authentifier à nouveau. Cela déjoue la tentative de piratage, l'attaquant est également obligé de se connecter au lieu d'accéder à la session. Avertissez l'utilisateur de la tentative (ajaxez-le un peu), et vola, l'utilisateur légèrement ennuyé + informé et sa session / information est protégée.

Nous ajoutons l'agent utilisateur 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. Vous pourrez peut-être utiliser plus d'informations que cela, n'hésitez pas à être créatif.

Ce n'est pas à 100%, mais c'est vraiment très efficace.

Vous pouvez faire plus pour protéger les sessions, les faire expirer, lorsqu'un utilisateur quitte un site Web et revient le forcer à se reconnecter peut-être. Vous pouvez détecter un utilisateur quittant et revenant en capturant un HTTP_REFERER vide (le domaine a été saisi dans la barre d'URL), ou vérifiez si la valeur de HTTP_REFERER est égale à votre domaine ou non (l'utilisateur a cliqué sur un lien externe / conçu pour accéder à votre site).

Expirez 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.

leuronyis
la source
3
J'ai déjà rencontré une situation dans laquelle un certain FAI (assez important, mais techniquement rétrograde) changerait l'adresse IP du navigateur de l'utilisateur de temps en temps en fonction du réacheminement des connexions de ses utilisateurs. Cela a fait que le chèque REMOTE_ADDR nous a renvoyé de faux négatifs.
goofballLogic
Pourquoi créer un hash? $_SESSION['ident'] = $aip . $bip . $agent;serait tout aussi sûr.
Dan Bray
2
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 continueront de changer et ils continueront à se déconnecter de leur compte.
Kareem
Qu'en est-il des proxys et des VPN? Toute personne utilisant un proxy TOR sera constamment déconnectée de son compte ... toutes les quelques minutes en fait.
Bradley
Même si vous oubliez cela, les adresses IP peuvent être manipulées par le client, donc cela ne dissuaderait pas un attaquant de toute façon.
Bradley
9

Essayez le protocole Secure Cookie décrit dans cet article par Liu, Kovacs, Huang et Gouda:

Comme indiqué dans le document:

Un protocole de cookie sécurisé qui s'exécute entre un client et un serveur doit fournir les quatre services suivants: authentification, confidentialité, intégrité et anti-relecture.

Quant à la facilité de déploiement:

En termes d'efficacité, notre protocole n'implique aucune recherche de base de données ni cryptographie à clé publique. En termes de déployabilité, notre protocole peut être facilement déployé sur un serveur Web existant et ne nécessite aucune modification de la spécification des cookies Internet.

En bref: il est sûr, léger, fonctionne pour moi tout simplement génial.

Hubert
la source
9
Votre lien est une spécification du protocole - avez-vous un lien vers une implémentation? Ce serait génial, merci.
Adam
9

Il n'y a aucun moyen d'empêcher le piratage de session à 100%, mais avec une certaine approche, nous pouvons réduire le temps pour un attaquant de détourner la session.

Méthode pour éviter le détournement de session:

1 - utilisez toujours la session avec un certificat SSL;

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

2 - utilisez l'identifiant 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 demande car si vous avez une requête ajax consécutive, vous avez la possibilité de créer plusieurs sessions.)

3 - Définissez un délai d'expiration de 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 de jeton et définissez l'heure d'expiration de ce cookie sur 0 (jusqu'à ce que le navigateur soit fermé). Régénérez la valeur du cookie pour chaque requête (pour une requête ajax, ne régénérez pas le cookie de 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 de jeton avec la requête ajax note: le code ci-dessus est un exemple. Remarque: si les utilisateurs se déconnectent, le jeton de cookie 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 piratage de session car certains utilisateurs changent d'IP à chaque demande. QUI AFFECTENT LES UTILISATEURS VALIDES

7 - Personnellement, je stocke les données de session dans la base de données, c'est à vous de décider quelle méthode vous adoptez

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

Alexandru
la source
salut, im essayant d'empêcher le détournement de session (dans ASP.NET) et considéré toutes les étapes ci-dessus u suggérées. Cela fonctionne approximativement, mais lorsque j'utilise le mode InPrivateBrowsing / incognito du navigateur, la session est piratée. Pouvez-vous suggérer quelque chose supplémentaire à ajouter dans la chaîne sessionId?
Vishwanath Mishra
4

Assurez-vous de ne pas utiliser de nombres entiers incrémentés pour les ID de session. Il est préférable d'utiliser un GUID ou une autre longue chaîne de caractères générée de manière aléatoire.

Kibbee
la source
3

Il existe de nombreuses façons de créer une protection contre le piratage de session, mais toutes réduisent la satisfaction des utilisateurs ou ne sont pas sécurisées.

  • Contrôles IP et / ou X-FORWARDED-FOR. Celles-ci fonctionnent et sont assez sécurisées ... mais imaginez la douleur des utilisateurs. Ils viennent dans un bureau avec WiFi, ils obtiennent une nouvelle adresse IP et perdent la session. Je dois vous reconnecter.

  • Vérifications de l'agent utilisateur. Comme ci-dessus, la nouvelle version du navigateur est sortie et vous perdez une session. De plus, ceux-ci sont vraiment faciles à «pirater». Il est trivial pour les pirates d'envoyer de fausses chaînes UA.

  • jeton localStorage. Lors de la connexion, générez un jeton, stockez-le dans le stockage du navigateur et stockez-le dans un cookie crypté (crypté côté serveur). Cela n'a aucun effet secondaire pour l'utilisateur (localStorage persiste pendant les mises à niveau du navigateur). Ce n'est pas aussi sûr - car ce n'est que la sécurité par l'obscurité. De plus, vous pouvez ajouter une logique (chiffrement / déchiffrement) à JS pour l'obscurcir davantage.

  • Cookie réédité. C'est probablement la bonne façon de procéder. L'astuce consiste à n'autoriser qu'un seul client à utiliser un cookie à la fois. Ainsi, l'utilisateur actif aura un cookie réémis toutes les heures ou moins. L'ancien cookie est invalidé si un nouveau est émis. Les piratages sont toujours possibles, mais beaucoup plus difficiles à faire - un pirate informatique ou un utilisateur valide obtiendra l'accès refusé.

la trappe
la source
1

Considérons que pendant la phase de connexion le client et le serveur peuvent s'entendre sur une valeur de sel secrète. Ensuite, le serveur fournit une valeur de comptage à chaque mise à jour et s'attend à ce que le client réponde avec le hachage du (sel secret + nombre). Le pirate de l'air potentiel n'a aucun moyen d'obtenir cette valeur de sel secrète et ne peut donc pas générer le hachage suivant.

Davej
la source
3
Mais comment voulez-vous stocker ce sel côté client afin que personne ne puisse le voler?
Dcortez
1

AFAIK l'objet de session n'est pas accessible chez le client, car il est stocké sur le serveur Web. Cependant, l'identifiant de session est stocké en tant que cookie et permet au serveur Web de suivre la session de l'utilisateur.

Pour empêcher le détournement de session à l'aide de l'ID de session, vous pouvez stocker une chaîne hachée à l'intérieur de l'objet de session, créée à l'aide d'une combinaison de deux attributs, adresse distante et port distant, accessibles sur le serveur Web à l'intérieur de l'objet de requête. Ces attributs lient la session utilisateur au navigateur dans lequel l'utilisateur s'est connecté.

Si l'utilisateur se connecte à partir d'un autre navigateur ou d'un mode incognito sur le même système, l'adresse IP restera la même, mais le port sera différent. Par conséquent, lors de l'accès à l'application, l'utilisateur se verrait attribuer un identifiant de session différent par le serveur Web.

Voici le code que j'ai implémenté et testé en copiant l'identifiant de session d'une session dans une autre. Cela fonctionne assez bien. S'il y a une échappatoire, dites-moi comment vous l'avez simulée.

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
    HttpSession session = request.getSession();
    String sessionKey = (String) session.getAttribute("sessionkey");
    String remoteAddr = request.getRemoteAddr();
    int remotePort = request.getRemotePort();
    String sha256Hex = DigestUtils.sha256Hex(remoteAddr + remotePort);
    if (sessionKey == null || sessionKey.isEmpty()) {
        session.setAttribute("sessionkey", sha256Hex);
        // save mapping to memory to track which user attempted
        Application.userSessionMap.put(sha256Hex, remoteAddr + remotePort);
    } else if (!sha256Hex.equals(sessionKey)) {
        session.invalidate();
        response.getWriter().append(Application.userSessionMap.get(sessionKey));
        response.getWriter().append(" attempted to hijack session id ").append(request.getRequestedSessionId()); 
        response.getWriter().append("of user ").append(Application.userSessionMap.get(sha256Hex));
        return;
    }
    response.getWriter().append("Valid Session\n");
}

J'ai utilisé l'algorithme SHA-2 pour hacher la valeur en utilisant l'exemple donné à SHA-256 Hashing at baeldung

Attendant vos commentaires avec hâte.

Jzf
la source
@zaph Je suis désolé, mais je n'ai pas ajouté la réponse pour gagner des représentants. Le point n'est pas non plus le cryptage SHA-2. Mais le fait que j'ai pu détecter l'utilisation du cookie d'identifiant de session d'un autre utilisateur dans la session d'un autre utilisateur, c'est-à-dire le détournement de session comme dans la question d'origine. J'ai testé ma solution et j'ai trouvé qu'elle fonctionnait. Mais je ne suis pas un expert en la matière, alors j'aimerais que la communauté vérifie si ma réponse est assez bonne. Vous pouvez peut-être voir ce que fait mon extrait de code et décider s'il répond à la question. Merci!
Jzf
@zaph Merci d'avoir signalé l'erreur. J'ai mis à jour ma réponse selon votre suggestion. Veuillez supprimer votre vote négatif si vous pensez que la réponse est utile.
Jzf
0

Pour réduire le risque, vous pouvez également associer l'adresse IP d'origine à la session. De cette façon, un attaquant doit se trouver dans le même réseau privé pour pouvoir utiliser la session.

La vérification des en-têtes de référence peut également être une option, mais ceux-ci sont plus facilement usurpés.

Jules César
la source
7
non, vous ne pouvez pas utiliser l'adresse IP d'origine, car elle peut changer - soit via des adresses IP dynamiques, modifiées lorsqu'un utilisateur est temporairement déconnecté, ou via l'utilisation (implicite ou explicite) d'une batterie de serveurs proxy. De plus, les pirates de l'air de session provenant du même FAI peuvent utiliser le même proxy et IP qu'un utilisateur légitime ...
Olaf Kock
1
PHP-Nuke a une bonne page sur leur approche de session, et ils expliquent en détail comment l'accrochage à l'IP ne fonctionne pas avec tous les FAI phpnuke.org
...
4
Les changements d'IP sont très courants chez les fournisseurs d'accès Internet mobile. Avec Vodafone, mon adresse IP change à CHAQUE demande.
Blaise
1
Un peu d'un vieux post mais pour faire avancer cela. Les IP sont comme mentionné une mauvaise idée. Comme mentionné, les utilisateurs mobiles ont tendance à parcourir les adresses IP. Certains FAI dans le passé avaient également des IP itinérantes (comme AOL), mais cette approche est de plus en plus populaire maintenant avec la pénurie d'IP IPv4. Ces FAI incluent Plus net et BT
Peter
-15

Protéger par:

$ip=$_SERVER['REMOTE_ADDER'];
$_SESSEION['ip']=$ip;
Nima
la source
12
Je ne vois pas ce que vous faites ici.
samayo