Ok, il y a deux problèmes distincts mais liés, et chacun est traité différemment.
Fixation de session
C'est là qu'un attaquant définit explicitement l'identifiant de session d'une session pour un utilisateur. En général, en PHP, cela se fait en leur donnant une URL comme http://www.example.com/index...?session_name=sessionid
. Une fois que l'attaquant donne l'URL au client, l'attaque est identique à une attaque de détournement de session.
Il existe plusieurs façons d'éviter la fixation de session (faites-les toutes):
Définissez session.use_trans_sid = 0
dans votre php.ini
fichier. Cela indiquera à PHP de ne pas inclure l'identifiant dans l'URL et de ne pas lire l'URL pour les identifiants.
Définissez session.use_only_cookies = 1
dans votre php.ini
fichier. Cela indiquera à PHP de ne jamais utiliser d'URL avec des identifiants 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
- Stockage d'informations sensibles dans la session
- Changer quoi que ce soit dans la session
- etc...
Détournement de session
C'est là qu'un attaquant récupère un identifiant de session et est capable d'envoyer des requêtes comme s'il s'agissait de cet utilisateur. Cela signifie que puisque l'attaquant possède l'identifiant, il est pratiquement impossible de les distinguer de l'utilisateur valide en ce qui concerne le serveur.
Vous ne pouvez pas empêcher directement le détournement de session. Vous pouvez cependant prendre des mesures 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 hash fort: session.hash_bits_per_character
dans php.ini
. Réglez ceci sur session.hash_bits_per_character = 5
. Bien que cela ne rende pas plus difficile la fissuration, cela fait une différence lorsque l'attaquant tente de deviner l'identifiant de session. L'ID sera plus court, mais utilisera plus de caractères.
Définissez une entropie supplémentaire avec session.entropy_file
et session.entropy_length
dans votre php.ini
fichier. Définissez le premier sur session.entropy_file = /dev/urandom
et le second sur le nombre d'octets qui seront lus à partir du fichier d'entropie, par exemple session.entropy_length = 256
.
Modifiez le nom de la session du PHPSESSID par défaut. Ceci est accompli en appelant session_name()
avec votre propre nom d'identifiant comme premier paramètre avant l'appel 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 de l'heure). Mais en fonction de votre cas d'utilisation, cela peut être une option ...
Faites souvent pivoter votre identifiant de session. Je ne ferais pas cela à chaque demande (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 détourne une session, vous ne voulez pas qu'il puisse l'utiliser trop longtemps.
Incluez l' agent utilisateur de$_SERVER['HTTP_USER_AGENT']
dans la session. En gros, lorsque 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 truqué, donc ce n'est pas fiable à 100%, mais c'est mieux que pas.
Incluez l' adresse IP de$_SERVER['REMOTE_ADDR']
l' utilisateur dans la session. En gros, lorsque la session démarre, stockez-la dans quelque chose comme $_SESSION['remote_ip']
. Cela peut être problématique de la part de certains FAI qui utilisent plusieurs adresses IP pour leurs utilisateurs (comme AOL le faisait auparavant). Mais si vous l'utilisez, ce sera beaucoup plus sûr. Le seul moyen 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 (comme les attaques MITM, etc.).
Incluez un jeton dans la session et du côté des navigateurs que vous incrémentez et comparez souvent. Fondamentalement, pour chaque demande, faites $_SESSION['counter']++
du côté serveur. Faites également quelque chose dans JS du côté des navigateurs pour faire de même (en utilisant un stockage local). Ensuite, lorsque vous envoyez une requête, prenez simplement un nonce d'un jeton et vérifiez que le nonce est le même sur le serveur. En faisant cela, vous devriez être en mesure de détecter une session détournée car l'attaquant n'aura pas le compteur exact, ou s'il le fait, vous aurez 2 systèmes transmettant le même nombre et pourrez dire qu'un est falsifié. Cela ne fonctionnera pas pour toutes les applications, mais c'est un moyen de lutter contre le problème.
Une note sur les deux
La différence entre la fixation de session et le détournement concerne uniquement la manière dont l'identifiant de session est compromis. Lors de la fixation, l'identifiant est mis à une valeur que l'attaquant connaît à l'avance. Dans Hijacking, il est soit deviné, soit 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é. Cela se produit de manière transparente avec le gestionnaire de session principal. Cependant, certains gestionnaires de session personnalisés qui utilisentsession_set_save_handler()
ne le font pas et sont susceptibles d'attaquer d'anciens identificateurs de session. Assurez-vous que si vous utilisez un gestionnaire de session personnalisé, que vous gardez une trace de l'identifiant que vous ouvrez, et si ce n'est pas le même que vous enregistrez que vous supprimez (ou modifiez) explicitement l'identifiant de l'ancien.
En utilisant le gestionnaire de session par défaut, vous pouvez simplement appeler session_regenerate_id(true)
. Cela supprimera les anciennes informations de session pour vous. L'ancien ID n'est plus valide et entraînera la création d'une nouvelle session si l'attaquant (ou n'importe qui d'autre d'ailleurs) essaie de l'utiliser. Soyez prudent avec les gestionnaires de session personnalisés ...
Détruire une session
Si vous allez détruire une session (lors de la déconnexion par exemple), assurez-vous de la détruire complètement. Cela inclut la désactivation du cookie. Utilisation session_destroy
:
function destroySession() {
$params = session_get_cookie_params();
setcookie(session_name(), '', time() - 42000,
$params["path"], $params["domain"],
$params["secure"], $params["httponly"]
);
session_destroy();
}