Exercice 3 : Gestion des Sessions

Implémentez un système de connexion sécurisé avec sessions PHP

PHP Intermédiaire

Objectifs

  1. Créer un système complet d'authentification
  2. Utiliser les sessions PHP pour maintenir la connexion
  3. Protéger contre les attaques par fixation de session
  4. Implémenter une déconnexion sécurisée
  5. Restreindre l'accès aux pages protégées

Concepts clés

  • session_start() - Initialise une session
  • $_SESSION - Superglobale pour stocker les données
  • session_regenerate_id() - Protège contre la fixation
  • session_destroy() - Termine une session
  • password_verify() - Validation des mots de passe

Page de connexion (login.php)

<?php
session_start();

// Si l'utilisateur est déjà connecté
if (isset($_SESSION['user_id'])) {
  header('Location: dashboard.php');
  exit;
}

// Traitement du formulaire
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  require_once 'includes/db.php';
  require_once 'includes/functions.php';

  $email = trim($_POST['email']);
  $password = $_POST['password'];

  // Validation
  if (empty($email) || empty($password)) {
    $_SESSION['error'] = 'Tous les champs sont obligatoires';
  } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $_SESSION['error'] = 'Email invalide';
  } else {
    // Vérification des identifiants
    $stmt = $pdo->prepare("SELECT id, password FROM users WHERE email = ?");
    $stmt->execute([$email]);
    $user = $stmt->fetch();

    if ($user && password_verify($password, $user['password'])) {
      // Connexion réussie
      session_regenerate_id(true); // Protection contre la fixation
      $_SESSION['user_id'] = $user['id'];
      $_SESSION['last_activity'] = time();
      header('Location: dashboard.php');
      exit;
    } else {
      $_SESSION['error'] = 'Identifiants incorrects';
    }
  }
}
?>

Page d'inscription (register.php)

<?php
session_start();

// Traitement du formulaire
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
  require_once 'includes/db.php';
  require_once 'includes/functions.php';

  $name = trim($_POST['name']);
  $email = trim($_POST['email']);
  $password = $_POST['password'];
  $confirm = $_POST['confirm_password'];

  // Validation
  if (empty($name) || empty($email) || empty($password)) {
    $_SESSION['error'] = 'Tous les champs sont obligatoires';
  } elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $_SESSION['error'] = 'Email invalide';
  } elseif ($password !== $confirm) {
    $_SESSION['error'] = 'Les mots de passe ne correspondent pas';
  } elseif (strlen($password) < 8) {
    $_SESSION['error'] = 'Le mot de passe doit faire 8 caractères minimum';
  } else {
    // Vérifier si l'email existe déjà
    $stmt = $pdo->prepare("SELECT id FROM users WHERE email = ?");
    $stmt->execute([$email]);
    if ($stmt->fetch()) {
      $_SESSION['error'] = 'Cet email est déjà utilisé';
    } else {
      // Création du compte
      $passwordHash = password_hash($password, PASSWORD_DEFAULT);
      $stmt = $pdo->prepare("INSERT INTO users (name, email, password) VALUES (?, ?, ?)");
      $stmt->execute([$name, $email, $passwordHash]);

      // Connexion automatique
      $_SESSION['user_id'] = $pdo->lastInsertId();
      $_SESSION['success'] = 'Inscription réussie !';
      header('Location: dashboard.php');
      exit;
    }
  }
}
?>

Page protégée (dashboard.php)

<?php
session_start();

// Rediriger si non connecté
if (!isset($_SESSION['user_id'])) {
  $_SESSION['error'] = 'Vous devez être connecté';
  header('Location: login.php');
  exit;
}

// Vérifier l'inactivité (30 minutes)
$inactive = 1800; // 30 min en secondes
if (isset($_SESSION['last_activity']) &&
    time() - $_SESSION['last_activity'] > $inactive) {
  session_unset();
  session_destroy();
  header('Location: login.php?timeout=1');
  exit;
}
$_SESSION['last_activity'] = time(); // Mettre à jour le timestamp

// Récupérer les infos utilisateur
require_once 'includes/db.php';
$stmt = $pdo->prepare("SELECT name, email FROM users WHERE id = ?");
$stmt->execute([$_SESSION['user_id']]);
$user = $stmt->fetch();
?>

Déconnexion (logout.php)

<?php
session_start();

// Effacer toutes les données de session
$_SESSION = array();

// Supprimer le cookie de session
if (ini_get("session.use_cookies")) {
  $params = session_get_cookie_params();
  setcookie(session_name(), '', time() - 42000,
    $params["path"], $params["domain"],
    $params["secure"], $params["httponly"]
  );
}

// Détruire la session
session_destroy();

// Rediriger vers la page de connexion
header('Location: login.php');
exit;
?>

Bonnes pratiques de sécurité

Sécurité des sessions

  • Toujours démarrer la session avec session_start() au début du script
  • Utiliser session_regenerate_id(true) après une connexion réussie
  • Configurer les cookies de session en HTTPOnly et Secure
  • Mettre en place un timeout de session (ex: 30 minutes)

Protection des données

  • Ne stockez jamais de mots de passe en clair - utilisez password_hash()
  • Validez et filtrez toutes les entrées utilisateur
  • Utilisez HTTPS pour protéger les données transitant par le réseau
  • Limitez les données stockées dans $_SESSION au strict nécessaire

Exercice pratique

À implémenter :

  1. Créez une base de données avec une table users (id, name, email, password)
  2. Développez le système d'inscription avec validation
  3. Implémentez la connexion avec vérification du mot de passe
  4. Créez une page protégée accessible seulement aux utilisateurs connectés
  5. Ajoutez une fonctionnalité de déconnexion
  6. Protégez contre les attaques par fixation de session

Solution complète