connexion et usage de session/cookie

Eléphanteau du PHP | 10 Messages

03 mai 2009, 05:19

Bonjour,

je vais utiliser des sessions d'identifaction pour la navigation sur mon site, et j'ai besoin d'être d'info sur la sécurité à ce niveau.

Quand on veut se connecter, je vérifie que couple login/mdp correspond à une entrée dans la base, puis je créé une session. Je sais pas si c'est utile de vérifier sur chaque page que les données en session correspondent toujours aux identifiants en bdd (donc une requête à faire à chaque fois pour ça). Un membre (ou un hacker :twisted: ) a t-il une possibilté quelconque de voir le contenu de $_SESSION ? Car pourquoi pas récupérer l'intégralité des infos du membre à la connexion, ça permet d'économiser une ou plusieurs requêtes (si le membre veut consulter son profil il aura déjà tout), ou bien c'est risqué mais qu'est ce que ça change.

Par ailleurs si le visiteur veut utiliser un cookie pour se connecter automatiquement à l'avenir, que dois je stocker dans ses cookie car je crois qu'on doit exclure le stockage de login et mdp dans les cookie. De plus, je pense que par rapport à ça il faut vérifier toutes les pages car si le visiteur atterit directement sur une page membre, je dois être en mesure à chaque fois de vérifier que ses cookies sont justes (donc une requete par page pour ça)

Qu'en pensez vous?

Mammouth du PHP | 693 Messages

03 mai 2009, 09:28

Les fichiers de session sont sur ton serveur. Je dirais que si quelqu'un arrive à y accéder, il arrive à accéder à tout, y compris à tes identifiants de connexion. Tu es donc mal...

Pour la question du cookie, en effet, il faut vérifier à chaque fois sa présence, commepour une session. Tu peux créer pour chaque membre un identifiant unique, qui n'apparaitra jamais, sauf pour les cookie.

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

03 mai 2009, 11:37

Il n'est pas utile de stocker la moindre info confidentielle dans les sessions. Tout ce qu'un pirate peut faire d'une session, c'est la voler pas la modifier (sauf accès au système de fichier du serveur, mais dans ce cas tout est déjà fini).

Donc pour marquer qu'un utilisateur est connecté, stocker simplement son ID en session est largement suffisant, pas besoin d'en faire des tonnes avec des tokens & cie, ça ne sert à rien pour la partie session.

Concernant le vol de session, c'est un risque qui n'est jamais nul. Pour résumer, il s'agit pour le pirate de voler le cookie de l'utilisateur, et de l'utiliser pour sa propre connexion. Côté serveur tu reçois le bon cookie, tu affectes donc la bonne session, et le pirate a ni vu ni connu pris la place de l'utilisateur honnête. Le voleur peut par exemple très facilement "scanner" un réseau Wifi mal protégé et intercepter les entêtes HTTP, qui contiennent les cookies (et hop, vol de session).
Il existe des pseudo-solutions, souvent basées sur l'adresse IP mais toutes apportent des désagréments (utilisateurs pour qui les sessions deviendront instables sur ton site) sans pour autant apporter une réelle solution puisqu'un pirate qui sait voler une session saura aussi très probablement faire de l'IP-spoofing (camoufler son adresse IP avec celle de son choix), voire carrément s'infiltrer sur le réseau de sa victime (toujours grâce aux Wifi mal protégés). Ma politique à ce sujet : on ne peut rien faire d'efficace, donc autant ne pas s'emmerder à inventer des solutions moisies et laisser courir. Aux utilisateurs de savoir protéger leurs infos !
Il existe une seule vraie solution qui consiste à protéger efficacement du scan d'entêtes HTTP (principale source de vol de sessions, le vol de fichier étant carrément anecdotique), c'est d'utiliser HTTPS sur tout son site.


Ensuite, concernant l'identification automatique par cookie de type "remember me", la solution la plus simple et sécurisé c'est d'attacher en base de données à chaque compte une "clé d'identification automatique", et de stocker dans le cookie une clé qui sera par exemple le MD5 de login + clé d'identification (l'important étant que ce soit une encryption injective type MD5, SHA1, etc... et basé sur la clé + une information fixe propre à l'utilisateur qui sert de sel).

Mieux que de longs discours, un peu de pseudo-pseudo-code :
/////
// Identification par cookie (peut être placée au début de chaque page par exemple)
/////
if (!connecte()) // l'utilisateur n'est pas connecté
{
  $cle = trouve_cle_identification(); // renvoie la valeur du cookie "remember me"
  if ($cle) // il a le cookie
  {
    $utilisateur = select_utilisateur("MD5(CONCAT(username, authkey)) = '%cle%'", array('cle' => $cle)); // trouve l'utilisateur en fonction de cette clé
    if ($utilisateur)
    {
      regenerer_cookie_identification(); // met à jour le champ "authkey" dans la base avec une chaine aléatoire de taille fixe, et met à jour le cookie correspondant
      connecter($utilisateur); // connecte l'utilisateur en remplissant la session
    }
    else
    {
      supprimer_cookie_identification(); // supprimer le cookie d'authentification, vu qu'il est invalide
    }
  }
}


/////
// Réception du formulaire d'identification
/////

if (post('remember_me')) // l'utilisateur a coché "se souvenir de moi"
{
  regenerer_cookie_identification();
}
[edit]Ajout du "else: supprimer_cookie_identification".[/edit]
Modifié en dernier par naholyr le 04 mai 2009, 17:35, modifié 1 fois.

Eléphanteau du PHP | 10 Messages

03 mai 2009, 13:28

Merci de ta réponse.
/////
// Identification par cookie (peut être placée au début de chaque page par exemple)
/////
if (!connecte()) // l'utilisateur n'est pas connecté
{
  $cle = trouve_cle_identification(); // renvoie la valeur du cookie "remember me"
  if ($cle) // il a le cookie
  {
    $utilisateur = select_utilisateur("MD5(CONCAT(username, authkey)) = '%cle%'", array('cle' => $cle)); // trouve l'utilisateur en fonction de cette clé
    if ($utilisateur)
    {
      regenerer_cookie_identification(); // met à jour le champ "authkey" dans la base avec une chaine aléatoire de taille fixe, et met à jour le cookie correspondant
      connecter($utilisateur); // connecte l'utilisateur en remplissant la session
    }
  }
}

Si je comprend bien la méthodologie, si le cookie existe je vérifie sa validité avec une requete. Si c'est valide je modifie la valeur de la clé dans la bdd. Donc 2 requêtes à faire sur chaque page rien que pour l'authentification. ça a l'air lourd comme ça mais si y a un choix à faire entre sécurité et performance je préfère la sécurité.

Et donc niveau session, je réactualise les infos à chaque fois. Je dois également régénérer l'identifiant de session j'imagine :)

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

03 mai 2009, 17:49

Si tu n'es pas trop parano tu peux ne pas recharger à chaque connexion la clé d'authentification, mais je préfère.
D'autant que les requêtes dont tu parles ne se font pas sur chaque page : elles ne se font qu'une fois puisqu'après l'utilisateur est connecté normalement ;)
Il manque sans doute une partie dans mon script : si l'utilisateur n'est pas connecté, si le cookie existe, mais que les infos du cookie ne permettent pas de l'identifier, alors supprimer le cookie (cela assure qu'on ne tente pas l'authentification à chaque page).

Eléphanteau du PHP | 10 Messages

03 mai 2009, 19:15

Pour vérifier que l'utilisateur est toujours connecté donc je m'assure que les variables de sessions existent toujours et dois je également en vérifier le contenu à chaque fois (donc faire une requete)? ça revient à me demander si l'utilisateur a une quelconque possibilité de modifier les données de sa session?

ViPHP
AB
ViPHP | 5818 Messages

04 mai 2009, 16:30

Pour vérifier que l'utilisateur est toujours connecté donc je m'assure que les variables de sessions existent toujours et dois je également en vérifier le contenu à chaque fois (donc faire une requete)? ça revient à me demander si l'utilisateur a une quelconque possibilité de modifier les données de sa session?
Donc pour marquer qu'un utilisateur est connecté, stocker simplement son ID en session est largement suffisant, pas besoin d'en faire des tonnes avec des tokens & cie, ça ne sert à rien pour la partie session.