PHP 5.6.0 released

Sessions et sécurité

Lien externe : » Session fixation

La gestion des sessions HTTP est au coeur de la sécurité sur le Web. Toute atténuation doit être mesurée afin d'assurer la sécurité des sessions. Les développeurs doivent activer/utiliser les configurations appropriées.

  • session.cookie_lifetime=0. La valeur 0 a une signification spéciale. Elle indique aux navigateurs de stocker les cookies dans un stockage permanent. Toutefois, lorsque le navigateur se termine, le cookie contenant l'ID de session est supprimé immédiatement. Si le développeur définie une valeur différente de 0, il peut permettre à d'autres utilisateurs d'utiliser l'ID de session. La plupart des applications doivent utiliser 0 pour cette option. Si l'auto-identification est nécessaire, implémentez votre propre fonctionalité d'auto-identification sécurisée. N'utilisez surtout pas l'ID de session pour cela.
  • session.use_cookies=On et session.use_only_cookies=On. Malgré le fait que les cookies HTTP ont quelques problèmes, ils restent la façon préférée de gérer l'ID de session. N'utilisez que les cookies pour la gestion de l'ID de session lorsque c'est possible. La plupart des applications utilisent le cookie pour l'ID de session.
  • session.use_strict_mode=On. Cette option empêche le module de session d'utiliser un ID de session non initialisé. Dans d'autres termes, le module de session n'acceptera qu'un ID de session valide généré par le module de session. Il rejètera un ID de session fourni par les utilisateurs. Un injection d'ID de session peut être réalisé par un injection de cookie via Javascript de façon permanente ou temporaire. Lorsque la transparence de session est actif, l'ID de session peut être injecté via une chaîne de requête ou un paramètre de formulaire. Il n'y a aucune raison d'accepter un ID de session fourni par l'utilisateur, la plupart des applications ne doivent pas accepter des ID de session non initialisés fournis par l'utilisateur.
  • session.cookie_httponly=On. Désactive l'accès au cookie de session par Javascript. Cette option évite le vol de cookie par injection Javascript. Il est possible d'utiliser l'ID de session comme clé de protection CSRF, mais ce n'est pas recommandé. Par exemple, le source HTML peut être sauvegardé puis envoyé à d'autres utilisateurs. Pour une meilleure sécurité, le développeur ne doit pas écrire l'ID de session dans une page Web. La plupart des applications doivent utiliser l'attribut httponly pour le cookie contenant l'ID de session.
  • session.cookie_secure=On. Autorise l'accès au cookie contenant l'ID de session lorsque le protocole est HTTPS. Si votre site Web est un site Web uniquement accessible via HTTPS, vous devez activer cette option. L'utilisation de HSTS doit être considérée pour les sites Web uniquement accessible en HTTPS.
  • session.gc_maxlifetime=[le plus petit possible]. GC est exécuté via des probabilité. Cette option ne garantie pas l'effacement de vieilles sessions. Quelques modules de gestionnaire de session n'utilisent pas cette option. Raportez-vous à la documentation sur les gestionnaires de session pour plus de détails. Aussi, les développeurs ne peuvent utiliser cette option et il est recommandé de la définir à la plus petite valeur possible. Ajutez à la fois l'option session.gc_probability et l'option session.gc_divisor afin d'effacer les anciennes sessions à une fréquence appropriée. Si l'auto-identification est nécessaire, implémentez votre propre fonctionalité d'auto-identification. N'utilisez pas l'ID de la durée de vie de la session pour cela.
  • session.use_trans_sid=Off. L'utilisation du gestionnaire transparent de l'ID de session n'est pas interdite. Vous pouvez l'utiliser lorsque c'est nécessaire. Cependant, sa désactivation va améliorer la sécurité en supprimant la possibilité d'injection d'ID de session et les fuites d'ID de session.
  • session.referer_check=[votre URL d'origine] Lorsque session.use_trans_sid est actif, utilisez cette option est recommandé si c'est possible. Elle réduit les risques d'injection d'ID de session. Si votre site est http://example.com/, définissez cette option à http://example.com/. Notez que lorsque HTTPS est utilisé, le navigateur n'envoie pas l'en-tête referrer. Vi la configuration, le navigateur peut ne pas envoyer l'en-tête referrer. Toutefois, cette option n'est pas une mesure de sécurité fiable.
  • session.cache_limiter=nocache. Vous assure que le contenu HTTP n'est pas mis en cache pour l'identification de session. Autorise la mise en cache uniquement lorsque le contenu n'est pas privé. Sinon, le contenu serait exposé. "private" peut être utilisé si le contenu HTTP ne contient pas de données sensibles d'un point de vue sécurité. Notez que "private" va garder les données privées en cache pour les clients partagés. "public" peut être utilisé seulement lorsque le contenu HTTP ne contient pas du tout de données privées.
  • session.hash_function="sha256". Une fonction de hashage forte va générer un ID de session fort. Cependant, les collisions de hashage peuvent survenir avec le hash MD5 ; les développeurs doivent utiliser SHA-2 ou supérieures pour réaliser cette tâche. Les développeurs peuvent vouloir utiliser des hashes plus forts comme sha384 et sha512.

Le module de session ne garantie pas que l'information stockée dans une session n'est seulement vue par l'utilisation qui l'a créée. Vous devez prendre des mesures complémentaires pour protéger activement la confidentialité de la session, suivant la valeur associée.

Évaluer l'importance des données transportées par vos sessions et déployez des protections supplémentaires -- cela a généralement un prix, et réduit la commodité pour l'utilisateur. Par exemple, si vous voulez protéger les utilisateurs de simples tactiques d'ingénierie sociale, vous devez activer session.use_only_cookies. Dans ce cas, les cookies doivent obligatoirement être activés côté utilisateur, sinon les sessions ne fonctionneront pas.

Il y a plusieurs façons d'exposer un ID de session existant vers une autre partie. Il lui sera alors possible d'accéder à toutes les ressources associées avec cet ID spécifique. Tout d'abord, les URLs contiennent les IDs de session. Si vous liez vers un site externe, l'URL incluent l'ID de session peut être stockée dans les logs du serveurs externes via le referrer. Deuxièmement, un attaquant plus actif peut écouter votre traffic réseau. S'il n'est pas crypté, les IDs de session vont transiter en clair sur le réseau. La solution ici est d'implémenter SSL sur votre serveur et le rendre obligatoire pour les utilisateurs. HSTS peut être utilisé pour cela.

Depuis PHP 5.5.2, session.use_strict_mode est disponible. Lorsqu'il est actif, et que le module de gestionnaire de sauvegarde le supporte, les IDs de session non initialisés seront rejectés et un nouvel ID de session sera créé. Cela protège des attaques en forcant l'utilisateur à utiliser un ID de session connu. Les attaquants peuvent passer des liens ou envoyer des mails qui contiennent un ID de session. i.e. http://example.com/page.php?PHPSESSID=123456789 Si session.use_trans_sid est actif, la victime va démarrer une session en utilisant l'ID de session fourni par l'attaquant. session.use_strict_mode limite ce type de risque.

Malgré le fait que session.use_strict_mode limite les risques, les attaquants peuvent forcer les utilisateurs à utiliser un ID de session initialisé, créé par l'attaquant. Tout ce que l'attaquant a à faire est d'initialiser un ID de session avant l'attaque et de le garder actif.

Le cookie d'ID de session peut être défini avec des attributs de domaine, de chemin, en HTTP seulement, et de sécurité. C'est la priorité définie par les navigateurs. En utilisant la priorité, l'attaquant peut définir l'ID de session qui peut être utilisé de façon permanente. L'utilisation de session.use_only_cookies ne va pas résoudre ce problème. session.use_strict_mode va limiter ce risque. Avec session.use_strict_mode=On, l'ID de session non initialisé ne sera pas accepté. Le module de session créera tojours un nouvel ID de session lorsque l'ID de session n'est pas initialisé par le module de session. Ceci peut résulter en un Dos pour la victime, mais un DoS est plus acceptable qu'un compte compromis.

session.use_strict_mode est un bon compromis, mais n'est pas suffisant pour les sessions authentifiées. Les développeurs doivent utiliser la fonction session_regenerate_id() pour l'authentification. session_regenerate_id() doit être appelée avant de définir les informations d'authentification à $_SESSION. La fonction session_regenerate_id() assure que la nouvelle session contient les informations d'authentification stockées seulement dans une nouvelle session. i.e. Les erreurs durant le processus d'authentification peut sauvegarder les drapeaux authentifiés dans l'ancienne session.

L'appel à la fonction session_regenerate_id() peut résulter en un DoS personnel comme use_strict_mode=On. Cependant, un DoS est préférable à un compte compromis. L'ID de session doit être re-généré au moins lors de l'authentification La re-génération de l'ID de session réduit le risque de son vol, ceci pouvant être périodiquement appelé. Les développeurs ne doivent pas se fier à l'expiration de l'ID de session. Les attaquants peuvent accéder à l'ID de session périodiquement pour éviter son expiration. Les développeurs doivent implémenter leurs propres fonctionalités d'expiration pour les anciennes sessions.

Notez que la fonction session_regenerate_id() ne supprime pas les anciennes sessions par défaut. Les anciennes sessions d'authentification peuvent être disponibles pour utilisation. Si le développeur veut éviter l'utilisation d'anciennes sessions d'authentification par quiconque, il doit détruire la session en définissant l'option delete_old_session à TRUE. Cependant, l'effacement immédiat des anciennes sessions a des effets de bord. La session peut disparaîte lors de connexions concurrentes à l'application Web et/ou lorsque le réseau devient instable. Au lieu de supprimer immédiatement les anciennes sessions, vous pouvez définir un délai d'expiration très court dans $_SESSION vous même. Si l'utilisateur accède à une session obsolète (session expirée), vous interdisez son accès.

session.use_only_cookies et une bonne utilisation de session_regenerate_id() peuvent engendrer un DoS personnel. Lorsque c'est le cas, vous pouvez demander à l'utilisateur de supprimer les cookies et alerter les utilisateurs qu'il y a un éventuel risque quant à la sécurité. Les attaquants peuvent définir des cookies malicieux via des applications Web vulnérables (i.e. injection JavaScript), via des plugins de navigateur vulnérables/malicieux, etc...

Les développeurs ne doivent pas utiliser un ID de session avec une grande durée de vie pour l'identification automatique car il accroit les risques de vol de session. L'auto-identification doit être implémentée par le développeurs. Utilisez une clé de hashage sécurisé à usage unique pour l'auto-identification en utilisant les cookies. Utilisez un hashage fort et plus sécurisé que SHA-2. i.e. SHA-256 ou supérieurs avec des données aléatoires provenant de /dev/urandom ou équivalent. Si l'utilisateur n'est pas authentifié, vérifiez si la clé d'auto-identification sécurisé à usage unique est valide ou non. Si la clé est valide, authentifiez l'utilisateur et définissez une nouvelle clé d'auto-identification à usage unique. La clé d'auto-identification est une clé d'authentification avec une grande durée de vie ; elle doit être protégée autant que possible. Utilisez les attributs path/httponly/secure des cookies pour la protéger. Le développeur doit implémenter la fonctionalité qui désactive l'auto-identification et qui supprime les cookies contenant les clés d'auto-identification non nécessaire pour les utilisateurs.

add a note add a note

User Contributed Notes 5 notes

up
34
Anurag Jain
5 years ago
Websites which have sensitive information need to be patched to ensure its not exploited because of session issues.

In earlier versions of apache cookie reliability was not assumed and hence the default method was always using url-rewrite which meant every url link, every form submission etc would have a PHPSESSID=<sessionid> passed along to inform the server about the active session. New versions have turned this off using

session.use_trans_sid = 0

in the /etc/php5/apache2/php.ini file.

Reasons?
Well one might safe the offline page as a bookmark or pass the link across to others not realizing that the session id information is also sent. So someone who quickly accesses these pages could possible get logged on, this was also true wrt search engines, and I guess in some cases it being seen as duplicate content as the same page will have a different session id every time the robots scan the website.

But having this set does not mean you are protected. Let me explain.
What prevents me from presetting the session id! Assume there is a banking site www.example.com which has a login screen at www.example.com/login.php
I can send you can email with a link to the bank site as http://www.example.com/login.php?PHPSESSID=12345
When you click on the link it presents the session id as 12345 rather then asking the server to generate a new one. This is called session fixation. Keep in mind even with session.use_trans_sid = 0 this will work as this sets it only not to use url-rewrite. To prevent this altogether set session.use_only_cookies = 1 which ensures that only cookies will be used, but this could cause problems when dealing with transaction which involve switch sites, i.e. siteA forwards to site B for payment which forwards to siteA for thank you, in which case a phpsessid inform might be used to revive the old session.

A good approach would always be to at the login screen and immediately post login to force a new session id generated using random numbers

session_start();
$newsessid = somerandomnumberfunction();
session_id($newsessid);

you can also use session_regenerate_id() function to generate a new id

session_start();
session_regenerate_id();

Also its always good to ensure every valid session is checked against an ip. One good method is to store the session id and remote ip information in a table, or better store the ip as a session variable itself, once the user logs in and ensure that this is continued for remaining pages for security. This ofcourse wont work when users use the same office or shared network as the ip to the outside world is the same.

https is always a good idea for sensitive sites, but keeping it persistent for all pages which use session is important if you really want a foolproof system else anyone can always sniff your packets.

So to quickly go through the bits

- set session.use_trans_sid = 0 in /etc/php5/apache2/php.ini file.
- Ensure you always use a new self generated session id on successful login attempt.
- Try setting session.use_only_cookies = 1 and check if all works fine.
- Use https throughout to ensure no one can sniff your session id.
- Store session id, remote IP information and compare for successive pages
up
6
bmearns at ieee dot org
5 years ago
In addition to ip-address binding not always being effective, it can also prevent users connecting through a proxy-pool from even being able to use your site. In such a scenario, a person's IP address may very well change with every access.

If you're handling anything remotely secure, the only safe option is HTTPS. If the data doesn't need to be that secure, than you should not allow a high-jacked session to do too much damage. Basically, don't assume that a person really is who they pretend to be just because the session says a person authenticated with a username and password: it may have been that person who logged in, but that doesn't mean it's still that person. So if you're going to do something like change passwords or something, require them to authenticate again on the same form.

Of course this needs to be done in some secure way, as well, so that the password is not just floating over the network. A good way to do this is sending a nonce (number-used-once) along with the form and some javascript to concatenate the nonce to the password, then perform a cryptographic hash of the combined string. The resulting valid-once "password" should then be sent instead of the plain text password. To be effective, you also need to prevent people from using the form if they don't have JavaScript enabled. You can do this by disabling the form fields in HTML, then re-enabling them in JavaScript.
up
2
justin at fatbird dot ca
5 years ago
IP checking is a sometimes useful feature with two limitations that are important to be aware of:

1. Anyone surfing behind a proxy (e.g., someone at work) will provide the proxy's IP, not his own.  Session ID replay attacks will not be prevented by IP checking for an attacker on the user's side of the proxy.

2. If the PHP application is behind a reverse proxy, the reverse proxy's IP address will be the only request IP seen by PHP, so IP checking is useless.
up
-2
JonathanFeller at NOSPAMgmx dot ch
5 years ago
Perhaps, you would also like to timeout a session after some idle time. I noticed that session.gc_maxlifetime is not suitable for this. So I used this code to do the job:

<?php
if (!isset($_SESSION['timeout_idle'])) {
   
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
} else {
    if (
$_SESSION['timeout_idle'] < time()) {   
       
//destroy session
   
} else {
       
$_SESSION['timeout_idle'] = time() + MAX_IDLE_TIME;
    }
}
?>
up
-2
Olle Bergkvist
5 years ago
It is also quite important to (somehow) make sure that the cookies you're setting (including the session cookie) is only visible to the site that created it (or to other trusted sites only).

If the cookie's path is set to '/' (the whole domain), then any website on the same domain (might be lots of websites) _will_ get the cookie through HTTP headers and could possibly hijack your session.

One slightly acceptable protection would be to lock a session to one IP adress.
To Top