Dans le domaine de la sécurité des réseaux informatiques, les attaques par fixation de session tentent d' exploiter la vulnérabilité d'un système qui permet à une personne de fixer (trouver ou définir) l'identifiant de session d'une autre personne . La plupart des attaques par fixation de session sont basées sur le Web et la plupart s'appuient sur l'acceptation des identifiants de session à partir d'URL ( chaîne de requête ) ou de données POST.
Scénarios d'attaque
Alice a un compte à la banquehttp://unsafe.example.com/
Mallory a l'intention de cibler l'argent d'Alice de sa banque.
Alice a un niveau de confiance raisonnable en Mallory et visitera les liens que Mallory lui envoie.
Un scénario d'attaque simple
Scénario simple :
- Mallory a déterminé qu'il
http://unsafe.example.com/accepte n'importe quel identifiant de session, accepte les identifiants de session à partir de chaînes de requête et n'a aucune validation de sécurité.http://unsafe.example.com/n'est donc pas sécurisé. - Mallory envoie un e-mail à Alice : « Hé, regarde ça, il y a une nouvelle fonctionnalité de résumé de compte intéressante sur notre banque.
http://unsafe.example.com/?SID=I_WILL_KNOW_THE_SID» Mallory essaie de fixer le SID àI_WILL_KNOW_THE_SID. - Alice est intéressée et rend visite à
http://unsafe.example.com/?SID=I_WILL_KNOW_THE_SID. L'écran de connexion habituel apparaît et Alice se connecte. - Mallory rend visite à Alice
http://unsafe.example.com/?SID=I_WILL_KNOW_THE_SIDet dispose désormais d'un accès illimité au compte d'Alice.
Attaque utilisant le SID généré par le serveur
Une idée fausse est que si un serveur accepte uniquement les identifiants de session générés par le serveur, il est à l'abri d'une fixation. C'est faux .
Scénario:
- Mallory visite
http://vulnerable.example.com/et vérifie quel SID est renvoyé. Par exemple, le serveur peut répondre :Set-Cookie: SID=0D6441FEA4496C2. - Mallory peut désormais envoyer un e-mail à Alice : « Découvrez cette nouvelle fonctionnalité intéressante de notre banque,
http://vulnerable.example.com/?SID=0D6441FEA4496C2. » - Alice se connecte avec l'identifiant de session fixé
SID=0D6441FEA4496C2. - Mallory rend visite à Alice
http://vulnerable.example.com/?SID=0D6441FEA4496C2et dispose désormais d'un accès illimité au compte d'Alice.
Attaques utilisant des cookies inter-sous-domaines
Ce type d'attaque est similaire à une attaque cross-site cookie, à la différence qu'elle ne repose pas sur la vulnérabilité du navigateur de l'utilisateur. Elle repose plutôt sur le fait que les cookies génériques peuvent être définis par un sous-domaine et que ces cookies peuvent affecter d'autres sous-domaines.
Scénario:
- Un site Web
www.example.comdistribue des sous-domaines à des tiers non fiables - L'un de ces partis, Mallory, qui contrôle désormais
evil.example.com, attire Alice sur son site - Une visite sur le navigateur d'Alice
evil.example.comcrée un cookie de session avec le domaine.example.com - Lorsqu'Alice visite,
www.example.comce cookie sera envoyé avec la demande et Alice aura la session spécifiée par le cookie de Mallory. - Si Alice se connecte maintenant, Mallory peut utiliser son compte.
Une fois cette attaque terminée, Mallory peut accéder au www.example.comrôle d'Alice.
Il n'est pas indispensable qu'un utilisateur se connecte pour exploiter les attaques de fixation de session et, bien que ces attaques non authentifiées ne se limitent pas aux attaques de cookies inter-sous-domaines, les implications des attaques de sous-domaines sont pertinentes pour ces scénarios non authentifiés. Par exemple, Mallory peut fournir une URL de son site malveillant, fixer une session dans un scénario non authentifié et utiliser ces techniques pour exploiter sa cible. Cela inclut les scénarios exploitant à la fois les scénarios non authentifiés (par exemple les formulaires ou l'inscription) ainsi que la possibilité de fournir à l'utilisateur une session établie pour contourner complètement la connexion.
Considérez, par exemple, que Mallory peut créer un utilisateur A1ice sur www.example.com et se connecter à cet utilisateur pour capturer un identifiant de session valide et actuel. Mallory piège ensuite Alice avec une URL de evil.example.com qui fixe ce cookie de session dans le navigateur d'Alice (comme décrit ci-dessus) et redirige vers www.example.com pour finaliser une transaction particulière (ou, en fait, une utilisation plus large). Mallory est ainsi capable de fantômer la session à partir de sa connexion d'origine, de récupérer des données et d'exécuter des opérations en tant que « A1ice » sur « www.example.com ». Si Alice a été dupée avec succès et a enregistré sa carte de crédit sur le compte, Mallory pourrait alors effectuer des achats en utilisant cette carte.
Contre-mesures
N'acceptez pas les identifiants de session des variables GET / POST
Les identifiants de session dans l'URL (chaîne de requête, variables GET) ou les variables POST ne sont pas recommandés car ils simplifient cette attaque – il est facile de créer des liens ou des formulaires qui définissent des variables GET / POST.
- Le SID est divulgué à d'autres personnes lorsque les utilisateurs coupent et collent des « liens intéressants » depuis la barre d'adresse dans des chats, des forums, des communautés, etc.
- Le SID est stocké à de nombreux endroits (journal de l'historique du navigateur, journal du serveur Web, journaux proxy, ...)
Remarque : les cookies sont partagés entre les onglets et les fenêtres contextuelles du navigateur. Si votre système doit être connecté au même domaine (www.exemple.com/?code=site1 et www.exemple.com/?code=site2), les cookies peuvent entrer en conflit entre les onglets.
Il peut être nécessaire d'envoyer l'identifiant de session sur l'URL afin de surmonter cette limitation. Si possible, utilisez site1.example.com ou site2.example.com afin d'éviter tout conflit de domaine dans les cookies. Cela peut entraîner des coûts avec des certificats SSL supplémentaires.
Ce comportement peut être observé sur de nombreux sites en ouvrant un autre onglet et en essayant de faire des résultats de recherche côte à côte. L'une des sessions deviendra inutilisable.
Meilleure solution : confirmation d'identité
Cette attaque peut être largement évitée en modifiant l'ID de session lorsque les utilisateurs se connectent. Si chaque requête spécifique à un utilisateur nécessite que l'utilisateur soit authentifié (« connecté ») sur le site, un attaquant aurait besoin de connaître l'ID de la session de connexion de la victime. Cependant, lorsque la victime visite le lien avec l'ID de session fixe, elle devra se connecter à son compte pour faire quelque chose d'« important » en tant qu'elle-même. À ce stade, son ID de session changera et l'attaquant ne pourra rien faire d'« important » avec l'ID de session anonyme.
Une technique similaire peut être utilisée pour résoudre le problème du phishing . Si l'utilisateur protège son compte avec deux mots de passe, le problème peut être résolu dans une large mesure.
Cette technique est également utile contre les attaques de falsification de requêtes intersites .
Solution : stocker les identifiants de session dans les cookies HTTP
L'identifiant de session sur la plupart des systèmes modernes est stocké par défaut dans un cookie HTTP , qui présente un niveau de sécurité modéré tant que le système de session ne tient pas compte des valeurs GET/POST. Cependant, cette solution est vulnérable à la falsification de requêtes intersites et ne répond pas à l' exigence d'apatridie de REST .
Solution : utiliser l'identifiant de session SSL/TLS
Lors de l'activation de la sécurité HTTPS , certains systèmes permettent aux applications d'obtenir l' identifiant de session SSL/TLS . L'utilisation de l'identifiant de session SSL/TLS est très sécurisée, mais de nombreux langages de développement Web ne fournissent pas de fonctionnalités intégrées robustes pour cela.
Régénérer le SID à chaque requête
Une contre-mesure contre la fixation de session consiste à générer un nouvel identifiant de session (SID) à chaque requête. Si cela est fait, même si un attaquant parvient à tromper un utilisateur en lui faisant accepter un SID connu, le SID sera invalide lorsque l'attaquant tentera de le réutiliser. La mise en œuvre d'un tel système est simple, comme le montre ce qui suit :
- Obtenir l'identifiant de session précédent
OLD_SIDà partir de la requête HTTP. - Si
OLD_SIDest nul, vide ou si aucune session avec SID=OLD_SIDn'existe, créez une nouvelle session. - Générez un nouvel identifiant de session
NEW_SIDavec un générateur de nombres aléatoires sécurisé. - Que la session soit identifiée par SID=
NEW_SID(et non plus par SID=OLD_SID) - Transmettre le nouveau SID au client.
Exemple:
Si Mallory réussit à tromper Alice pour qu'elle lui rende visite http://victim.example.com/?SID=I_KNOW_THE_SID, cette requête HTTP est envoyée àvictim.example.com :
GET /?SID=JE_CONNAIS_LE_SID HTTP / 1.1 Hôte : victime.exemple.com
victim.example.comaccepte SID=I_KNOW_THE_SID, ce qui serait normalement mauvais. Cependant, victim.example.comest sécurisé car il effectue une régénération de session. victim.example.comobtient la réponse suivante :
HTTP / 1.1 200 OK Définir-Cookie : SID=3134998145AB331F
Alice va maintenant utiliser SID=3134998145AB331Fce qui est inconnu de Mallory et SID=I_KNOW_THE_SIDqui n'est pas valide. Mallory échoue donc dans sa tentative de fixation de session.
Malheureusement, la régénération de session n'est pas toujours possible. Des problèmes peuvent survenir lorsque des logiciels tiers tels que des applets ActiveX ou Java sont utilisés et lorsque des plugins de navigateur communiquent avec le serveur. Les logiciels tiers peuvent provoquer des déconnexions ou la session peut être divisée en deux sessions distinctes.
Si l'implémentation des sessions inclut la transmission du SID via des variables GET ou POST, cela peut également rendre le bouton « retour » de la plupart des navigateurs inutilisable, car l'utilisateur utiliserait alors un identifiant de session plus ancien et non valide provenant d'une demande précédente.
Accepter uniquement les SID générés par le serveur
Une façon d'améliorer la sécurité consiste à ne pas accepter les identifiants de session qui n'ont pas été générés par le serveur. Cependant, comme indiqué ci-dessus, cela n'empêche pas toutes les attaques de fixation de session.
if ( ! isset ( $_SESSION [ 'SERVER_GENERATED_SID' ])) { session_destroy (); // Détruire toutes les données de la session } session_regenerate_id (); // Génère un nouvel identifiant de session $_SESSION [ 'SERVER_GENERATED_SID' ] = true ;
Fonction de déconnexion
Une fonction de déconnexion est utile car elle permet aux utilisateurs d'indiquer qu'une session ne doit pas autoriser d'autres demandes. Ainsi, les attaques ne peuvent être efficaces que lorsqu'une session est active. Notez que le code suivant n'effectue aucune vérification de falsification de requête intersite , ce qui permet potentiellement à un attaquant de forcer les utilisateurs à se déconnecter de l'application Web.
if ( logout ) { session_destroy (); // Détruire toutes les données de la session }
Expiration du délai d'attente des anciens SID
Cette défense est simple à mettre en œuvre et présente l'avantage de fournir une mesure de protection contre les utilisateurs non autorisés accédant au compte d'un utilisateur autorisé en utilisant une machine qui aurait pu être laissée sans surveillance.
Stockez une variable de session contenant un horodatage du dernier accès effectué par ce SID. Lorsque ce SID est réutilisé, comparez l'horodatage actuel avec celui stocké dans la session. Si la différence est supérieure à un nombre prédéfini, par exemple 5 minutes, détruisez la session. Sinon, mettez à jour la variable de session avec l'horodatage actuel.
Détruire la session si le référent est suspect
Lorsque vous visitez une page, la plupart des navigateurs Web définissent l' en-tête Référent , c'est-à-dire la page qui contenait le lien que vous avez suivi pour accéder à cette page.
Lorsque l'utilisateur est connecté à un site qui n'est pas susceptible d'être lié à un site extérieur à ce site (par exemple, des sites Web bancaires ou des messageries Web ), et que le site n'est pas le type de site sur lequel les utilisateurs restent connectés pendant une longue période, le référent doit provenir de ce site. Tout autre référent doit être considéré comme suspect. Cependant, si la demande d'origine provient d'une page HTTPS, le référent sera supprimé, vous ne pouvez donc pas compter sur ce système de sécurité.
Par exemple, http://vulnerable.example.com/on pourrait utiliser le contrôle de sécurité suivant :
if ( strpos ( $_SERVER [ 'HTTP_REFERER' ], 'http://vulnerable.example.com/' ) !== 0 ) { session_destroy (); // Détruire toutes les données de la session } session_regenerate_id (); // Génère un nouvel identifiant de session
Vérifiez que les informations supplémentaires sont cohérentes tout au long de la session
Une façon d'améliorer encore la sécurité consiste à s'assurer que l'utilisateur semble être le même utilisateur final (client). Cela rend un peu plus difficile la fixation de session et d'autres attaques.
À mesure que de plus en plus de réseaux se conforment à la norme RFC 3704 et à d'autres pratiques anti- usurpation d'identité , l' adresse IP devient plus fiable en tant qu'identifiant de « même source ». Par conséquent, la sécurité d'un site Web peut être améliorée en vérifiant que l'adresse IP source est cohérente tout au long d'une session.
Cela pourrait être réalisé de cette manière :
if ( $_SERVER [ 'REMOTE_ADDR' ] != $_SESSION [ 'PREV_REMOTEADDR' ]) { session_destroy (); // Détruire toutes les données de la session } session_regenerate_id (); // Génère un nouvel identifiant de session $_SESSION [ 'PREV_REMOTEADDR' ] = $_SERVER [ 'REMOTE_ADDR' ];
Cependant, il y a quelques points à prendre en compte avant d’employer cette approche.
- Plusieurs utilisateurs peuvent partager une même adresse IP. Il n'est pas rare qu'un bâtiment entier partage une même adresse IP à l'aide de NAT .
- Un utilisateur peut avoir une adresse IP incohérente. Cela est vrai pour les utilisateurs derrière des proxys (tels que les clients AOL ). Cela est également vrai pour certains utilisateurs mobiles/itinérants, ainsi que pour les utilisateurs qui se trouvent derrière des connexions Internet à charge équilibrée. Les utilisateurs ayant activé les extensions de confidentialité IPv6 peuvent également modifier leurs adresses de confidentialité IPv6 à tout moment.
- Cela ne fonctionnera pas de manière fiable avec les clients à double pile, car les requêtes se déplaceront entre IPv4 et IPv6.
- Cela ne fonctionnera pas de manière fiable avec les utilisateurs mobiles, car ces derniers se déplacent également entre les adresses.
Pour certains sites, la sécurité supplémentaire l’emporte sur le manque de commodité, et pour d’autres, ce n’est pas le cas.
Agent utilisateur
Les navigateurs s'identifient grâce à des en-têtes HTTP « User-Agent ». Cet en-tête ne change normalement pas pendant l'utilisation ; il serait extrêmement suspect que cela se produise. Une application Web peut utiliser la détection d'agent utilisateur pour tenter d'empêcher les utilisateurs malveillants de voler des sessions. Il est cependant facile de contourner cette méthode, car un attaquant peut facilement capturer l'agent utilisateur de la victime avec son propre site, puis l'usurper pendant l'attaque. Ce système de sécurité proposé repose sur la sécurité par l'obscurité .
if ( $_SERVER [ 'HTTP_USER_AGENT' ] != $_SESSION [ 'PREV_USERAGENT' ]) { session_destroy (); // Détruire toutes les données de la session } session_regenerate_id (); // Génère un nouvel identifiant de session $_SESSION [ 'PREV_USERAGENT' ] = $_SERVER [ 'HTTP_USER_AGENT' ];
Cependant, il y a quelques points à prendre en compte avant d’employer cette approche.
- Plusieurs utilisateurs peuvent avoir le même agent utilisateur de navigateur dans un cybercafé .
- Plusieurs utilisateurs peuvent avoir le même navigateur par défaut (ex : Internet Explorer 6 sous Windows XP SP3 ou mini navigateur sur téléphone mobile).
Mais l'agent utilisateur peut changer légalement dans certains cas. Les exemples suivants concernent les mêmes utilisateurs.
- Un smartphone dont l'écran a tourné depuis la dernière requête
Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 854X480 motorola DROID2Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 Build/VZW) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 480X854 motorola DROID2
- Mode de compatibilité Internet Explorer :
Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; Trident/4.0; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)
- Un utilisateur accédant à un site Web via un proxy réparti sur plusieurs serveurs, qui ne sont pas tous mis à niveau vers la dernière version du logiciel proxy
Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/0.0.5; +http://flipboard.com/browserproxy)Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6 (FlipboardProxy/1.1; +http://flipboard.com/browserproxy)
Défense en profondeur
La défense en profondeur consiste à combiner plusieurs contre-mesures. L'idée est simple : si un obstacle est trivial à surmonter, plusieurs obstacles pourraient être très difficiles à surmonter.
Une stratégie de défense en profondeur pourrait impliquer :
- Activer HTTPS (pour se protéger contre d'autres problèmes)
- Configuration correcte (ne pas accepter les SID externes, définir un délai d'attente, etc.)
- Effectuer la régénération de session, prendre en charge la déconnexion, etc.
Les référents HTTP ne sont pas transmis avec SSL/TLS (HTTPS).
Le script PHP suivant illustre plusieurs de ces contre-mesures combinées de manière à assurer une défense en profondeur :
si ( isset ( $_GET [ 'LOGOUT' ]) || $_SERVER [ 'REMOTE_ADDR' ] !== $_SESSION [ 'PREV_REMOTEADDR' ] || $_SERVER [ 'HTTP_USER_AGENT' ] !== $_SESSION [ 'PREV_USERAGENT' ]) { session_destroy (); } session_regenerate_id (); // Générer un nouvel identifiant de session $_SESSION [ 'PREV_USERAGENT' ] = $_SERVER [ 'HTTP_USER_AGENT' ]; $_SESSION [ 'PREV_REMOTEADDR' ] = $_SERVER [ 'REMOTE_ADDR' ];
Notez que ce code compare l'adresse IP de l'utilisateur et l'agent utilisateur actuels à l'adresse REMOTE_ADDR et à l'agent utilisateur de la requête précédente. Cela peut être gênant pour certains sites, comme indiqué ci-dessus.