web-dev-qa-db-fra.com

PHP Fixation de session / piratage

J'essaie de mieux comprendre PHP Session Fixation & le piratage et la prévention de ces problèmes. J'ai lu les deux articles suivants sur le site Web de Chris Shiflett:

Cependant, je ne suis pas sûr de bien comprendre les choses.

Pour empêcher la fixation de session, il suffit d'appeler session_regenerate_id (true); après avoir connecté quelqu'un avec succès? Je pense que j'ai bien compris.

Il parle également de l'utilisation de jetons transmis dans les URL via $ _GET pour empêcher le détournement de session. Comment cela serait-il fait exactement? Je suppose que lorsque quelqu'un se connecte, vous générez son jeton et le stockez dans une variable de session, puis comparez cette variable de session à chaque page avec la valeur de la variable $ _GET?

Ce jeton doit-il être modifié une seule fois par session ou à chaque chargement de page?

Est-ce également un bon moyen de prévenir le détournement d’avions sans avoir à transmettre une valeur dans les urls? ce serait beaucoup plus facile.

145
me2

Ok, il y a deux problèmes distincts mais liés, et chacun est traité différemment.

Fixation de session

C’est là que l’attaquant définit explicitement l’identificateur de session d’une session pour un utilisateur. Généralement, dans PHP, vous devez leur donner une URL telle que http://www.example.com/index...?session_name=sessionid. Une fois que l'attaquant a transmis l'URL au client, l'attaque est identique à une attaque de piratage de session.

Il y a plusieurs façons d'empêcher la fixation de session (faites-les toutes):

  • Définissez session.use_trans_sid = 0 dans votre fichier php.ini. Cela dira à PHP de ne pas inclure l'identifiant dans l'URL et de ne pas lire l'URL des identificateurs.

  • Définissez session.use_only_cookies = 1 dans votre fichier php.ini. Cela indiquera à PHP de ne jamais utiliser d'URL avec des identificateurs de session.

  • Régénérez l'ID de session chaque fois que l'état de la session change. Cela signifie l'un des éléments suivants:

    • Authentification d'utilisateur
    • Stocker des informations sensibles dans la session
    • Changer quelque chose à propos de la session
    • etc...

Détournement de session

C'est à cet endroit qu'un attaquant s'empare d'un identifiant de session et peut envoyer des requêtes comme s'il était cet utilisateur. Cela signifie que l'attaquant ayant l'identifiant, il est impossible de les distinguer de l'utilisateur valide par rapport au serveur.

Vous ne pouvez pas empêcher directement le détournement de session. Vous pouvez toutefois mettre en place des étapes pour le rendre très difficile et plus difficile à utiliser.

  • Utilisez un identifiant de hachage de session fort: session.hash_function dans php.ini. Si PHP <5.3, définissez-le sur session.hash_function = 1 Pour SHA1. Si PHP> = 5.3, définissez-le sur session.hash_function = sha256 ou session.hash_function = sha512.

  • Envoyez un hachage fort: session.hash_bits_per_character dans php.ini. Définissez ceci sur session.hash_bits_per_character = 5. Bien que cela ne rende pas le plus difficile à craquer, cela fait une différence lorsque l'attaquant tente de deviner l'identifiant de la session. L'ID sera plus court, mais utilise plus de caractères.

  • Définissez une entropie supplémentaire avec session.entropy_file et session.entropy_length dans votre fichier php.ini. Définissez le premier sur session.entropy_file = /dev/urandom Et le dernier sur le nombre d'octets lus dans le fichier d'entropie, par exemple session.entropy_length = 256.

  • Modifiez le nom de la session à partir de PHPSESSID par défaut. Ceci est accompli en appelant session_name() avec votre propre identifiant comme premier paramètre avant d'appeler session_start.

  • Si vous êtes vraiment paranoïaque, vous pouvez également faire pivoter le nom de la session, mais sachez que toutes les sessions seront automatiquement invalidées si vous le modifiez (par exemple, si vous le rendez dépendant du temps). Mais selon votre cas d'utilisation, cela peut être une option ...

  • Faites souvent pivoter votre identifiant de session. Je ne ferais pas cela à chaque requête (sauf si vous avez vraiment besoin de ce niveau de sécurité), mais à un intervalle aléatoire. Vous voulez changer cela souvent car si un attaquant pirate une session, vous ne voulez pas qu'ils puissent l'utiliser trop longtemps.

  • Incluez le agent utilisateur de $_SERVER['HTTP_USER_AGENT'] dans la session. En gros, quand la session démarre, stockez-la dans quelque chose comme $_SESSION['user_agent']. Ensuite, à chaque demande suivante, vérifiez qu’elle correspond. Notez que cela peut être simulé, donc ce n’est pas fiable à 100%, mais c’est mieux qu’autrement.

  • Incluez le adresse IP de l'utilisateur de $_SERVER['REMOTE_ADDR'] dans la session. En gros, quand la session démarre, stockez-la dans quelque chose comme $_SESSION['remote_ip']. Cela peut être problématique chez certains fournisseurs de services Internet qui utilisent plusieurs adresses IP pour leurs utilisateurs (comme AOL le faisait auparavant). Mais si vous l'utilisez, ce sera beaucoup plus sécurisé. La seule façon pour un attaquant de simuler l'adresse IP est de compromettre le réseau à un moment donné entre l'utilisateur réel et vous. Et s'ils compromettent le réseau, ils peuvent faire bien pire qu'un détournement d'avion (comme des attaques MITM, etc.).

  • Incluez un jeton dans la session et dans les navigateurs que vous incrémentez et comparez souvent. En gros, pour chaque demande, faites $_SESSION['counter']++ Côté serveur. Faites également quelque chose dans JS du côté des navigateurs pour faire la même chose (en utilisant un stockage local). Ensuite, lorsque vous envoyez une demande, prenez simplement le nonce d'un jeton et vérifiez que le nonce est le même sur le serveur. En faisant cela, vous devriez pouvoir détecter une session détournée, car l'attaquant n'aura pas le compteur exact. Sinon, vous aurez 2 systèmes qui transmettent le même nombre et vous pouvez savoir qu'un est falsifié. Cela ne fonctionnera pas pour toutes les applications, mais constitue un moyen de lutter contre le problème.

Une note sur les deux

La différence entre la fixation de session et le piratage concerne uniquement la manière dont l'identificateur de session est compromis. Dans la fixation, l'identifiant est défini sur une valeur que l'attaquant connaît d'avance. Dans Hijacking, il est deviné ou volé à l'utilisateur. Sinon, les effets des deux sont les mêmes une fois que l'identifiant est compromis.

Régénération d'identifiant de session

Chaque fois que vous régénérez l'identifiant de session en utilisant session_regenerate_id l'ancienne session doit être supprimée. Cela se produit de manière transparente avec le gestionnaire de session principal. Cependant, certains gestionnaires de session personnalisés utilisant session_set_save_handler() ne le font pas et sont prêts à attaquer d'anciens identificateurs de session. Assurez-vous que si vous utilisez un gestionnaire de session personnalisé, vous gardez une trace de l'identifiant que vous avez ouvert et si ce n'est pas le même que vous sauvegardez, vous supprimez explicitement (ou modifiez) l'identifiant de l'ancien.

En utilisant le gestionnaire de session par défaut, vous n’avez qu’à appeler session_regenerate_id(true). Cela supprimera les informations de l'ancienne session pour vous. L'ancien ID n'est plus valide et entraînera la création d'une nouvelle session si l'attaquant (ou toute autre personne) tente de l'utiliser. Soyez prudent avec les gestionnaires de session personnalisés cependant ....

Détruire une session

Si vous voulez détruire une session (à la déconnexion, par exemple), assurez-vous de la détruire complètement. Cela inclut la désactivation du cookie. Utiliser session_destroy :

function destroySession() {
    $params = session_get_cookie_params();
    setcookie(session_name(), '', time() - 42000,
        $params["path"], $params["domain"],
        $params["secure"], $params["httponly"]
    );
    session_destroy();
}
216
ircmaxell

Les deux attaques de session ont le même objectif: accéder à une session légitime d'un autre utilisateur. Mais les vecteurs d'attaque sont différents:

  • Dans une attaque Session Fixation , l'attaquant a déjà accès à une session valide et tente de forcer la victime à utiliser cette session particulière.

  • Dans une attaque de détournement de session , l'attaquant tente d'obtenir l'ID de la session d'une victime pour qu'il l'utilise.

Dans les deux attaques, l'ID de session correspond aux données sensibles sur lesquelles se concentrent ces attaques. Il s’agit donc de l’ID de session à protéger à la fois pour un accès en lecture (détournement de session) et pour un accès en écriture (fixation de session).

La règle générale de protection des données sensibles à l'aide de HTTPS s'applique également dans ce cas. De plus, vous devriez faire ce qui suit:

Pour empêcher les attaques par fixation de session , assurez-vous que:

Pour éviter les attaques de piratage de session , assurez-vous que:

Pour empêcher les deux attaques de session, assurez-vous que:

  • accepter uniquement les sessions que votre application a lancées. Pour ce faire, vous devez identifier une session lors de l’initiation avec des informations spécifiques au client. Vous pouvez utiliser l’ID User-Agent, mais n’utilisez pas l’adresse IP distante ni toute autre information susceptible de changer entre les demandes.
  • pour changer l'ID de session en utilisant session_regenerate_id(true) après une tentative d'authentification (true uniquement en cas de succès) ou un changement de privilèges et détruire l'ancienne session. (Assurez-vous de stocker toutes les modifications de $_SESSION En utilisant session_write_close avant en régénérant l'ID si vous souhaitez conserver la session associée à l'ancien ID; sinon, seule la session avec le nouvel ID sera affectée par ces modifications.)
  • d'utiliser une implémentation d'expiration de session appropriée (voir Comment puis-je expirer une PHP après 30 minutes? ).
37
Gumbo

Les jetons que vous mentionnez sont un "nonce" - numéro utilisé une fois. Ils ne doivent pas nécessairement être utilisés qu'une seule fois, mais plus ils sont utilisés longtemps, plus les chances que le nonce puisse être capturé et utilisé pour détourner la session soient élevées.

Un autre inconvénient des nonces est qu’il est très difficile de construire un système qui les utilise et qui autorise plusieurs fenêtres parallèles sur le même formulaire. par exemple. l'utilisateur ouvre deux fenêtres sur un forum et commence à travailler sur deux articles:

window 'A' loads first and gets nonce 'P'
window 'B' loads second and gets nonce 'Q'

Si vous ne pouvez pas suivre plusieurs fenêtres, vous n’avez stocké qu’un seul compte - celui de la fenêtre B/Q. Lorsque l’utilisateur soumet ensuite son message à partir de la fenêtre A et passe au nonce "P", le système refuse le message en tant que P != Q.

6
Marc B

Je n'ai pas lu l'article de Shiflett, mais je pense que vous avez mal compris quelque chose.

Par défaut PHP transmet le jeton de session dans l'URL chaque fois que le client n'accepte pas les cookies. Sinon, dans le cas le plus courant, le jeton de session est stocké en tant que cookie.

Cela signifie que si vous insérez un jeton de session dans l'URL PHP le reconnaîtra et tentera de l'utiliser ultérieurement. La fixation de session survient lorsque quelqu'un crée une session et incite un autre utilisateur à partager la même session. en ouvrant une URL contenant le jeton de session.Si l'utilisateur s'authentifie d'une manière ou d'une autre, l'utilisateur malveillant connaît alors le jeton de session d'un authentifié, qui peut avoir des privilèges différents.

Comme l'explique Shiflett, je suis sûr que la chose habituelle à faire est de régénérer un jeton différent chaque fois que les privilèges d'un utilisateur changent.

2
Andrea

Oui, vous pouvez empêcher la fixation de session en régénérant l'identifiant de session une fois connecté. De cette façon, si l'attaquant ne connait pas la valeur du cookie de la session nouvellement authentifiée. Une autre approche qui arrête totalement le problème est définie session.use_only_cookies=True dans votre configuration d'exécution. Un attaquant ne peut pas définir la valeur d'un cookie dans le contexte d'un autre domaine. La fixation de session repose sur l'envoi de la valeur de cookie sous forme de GET ou de POST.

0
rook