Aller au contenu principal

Attaques sur les sessions

Attaques sur les sessions et contre-mesures

Notions théoriques

1. Qu'est-ce qu'une session ?

Une session est un mécanisme permettant à un serveur de suivre l'état d'un utilisateur sur un site Web.

Lorsqu'un utilisateur se connecte, un identifiant de session (souvent un cookie) est généré et stocké dans le navigateur.

Cet identifiant est envoyé au serveur à chaque requête pour authentifier l'utilisateur.

2. Les attaques sur les sessions

Les sessions peuvent être ciblées par plusieurs types d'attaques :

a) Session Hijacking (Détournement de session)

Un attaquant intercepte l'identifiant de session d'un utilisateur pour se faire passer pour lui. Cela peut se produire si la connexion n'est pas sécurisée (HTTP au lieu de HTTPS) ou si le cookie est accessible via des scripts malveillants.

b) Session Fixation

L'attaquant force la victime à utiliser un identifiant de session prédéfini. Si l'utilisateur s'authentifie avec cet identifiant, l'attaquant peut alors prendre le contrôle de la session.

c) Cross-Site Scripting (XSS) et vol de session

Une attaque XSS permet d'injecter du code JavaScript malveillant dans une page Web. Ce code peut voler les cookies de session et les envoyer à l'attaquant.

d) Cross-Site Request Forgery (CSRF)

Une attaque CSRF force un utilisateur authentifié à exécuter des actions non désirées sur un site Web où il est connecté. Par exemple, un lien malveillant pourrait déclencher un transfert d'argent à l'insu de l'utilisateur.

3. Contre-mesures

a) Utilisation de HTTPS

Le protocole HTTPS chiffre les communications entre le navigateur et le serveur, empêchant l'interception des identifiants de session.

b) Cookies sécurisés

  • HttpOnly : empêche l'accès aux cookies via JavaScript, réduisant le risque de vol par XSS.
  • Secure : assure que le cookie n'est transmis que via HTTPS.
  • SameSite : empêche l'envoi des cookies lors de requêtes intersites, limitant les attaques CSRF.

c) Regénération de l'identifiant de session

Après chaque connexion ou action sensible, il est recommandé de générer un nouvel identifiant de session pour éviter les attaques par fixation de session.

d) Protection contre CSRF

  • Utilisation de tokens CSRF dans les formulaires.
  • Vérification de l'origine des requêtes.

Exemple pratique

Il est possible de sécuriser les sessions en appliquant plusieurs bonnes pratiques dans une application Node.js avec Express.

1. Installation des dépendances

mkdir secure-session
cd secure-session
npm init -y
npm install express express-session csurf helmet

2. Création du serveur avec des sessions sécurisées

const express = require("express");
const session = require("express-session");
const helmet = require("helmet");
const csrf = require("csurf");

const app = express();

// Sécurisation des en-têtes HTTP
app.use(helmet());

// Configuration de la session
app.use(session({
secret: "supersecretkey",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true, // Protège contre XSS
secure: false, // À mettre sur true en production avec HTTPS
sameSite: "strict" // Protège contre CSRF
}
}));

// Protection CSRF
const csrfProtection = csrf();
app.use(csrfProtection);

app.get("/", (req, res) => {
res.send(`Token CSRF : ${req.csrfToken()}`);
});

app.listen(3000, () => {
console.log("Serveur démarré sur http://localhost:3000");
});

Ce code met en place :

  • Helmet pour sécuriser les en-têtes HTTP.
  • express-session avec des options de sécurité.
  • CSRF tokens pour protéger contre les attaques CSRF.

Test de mémorisation/compréhension


Quel est le principal objectif d'une session Web ?


Comment un attaquant peut-il voler une session ?


Quelle attaque force un utilisateur à utiliser un identifiant de session prédéfini ?


Quel paramètre de cookie empêche l'accès via JavaScript ?


Quel protocole est essentiel pour protéger les sessions ?



TP pour réfléchir et résoudre des problèmes

Ce TP consiste à créer une application Web sécurisée contre les attaques sur les sessions.


Étape 1 : Initialisation du projet

Avant de commencer à coder, il est nécessaire de mettre en place un projet Node.js avec Express.

Instructions :

  1. Ouvrir un terminal et naviguer vers un dossier de travail.
  2. Créer un nouveau dossier pour le projet :
mkdir tp-secure-session
cd tp-secure-session
  1. Initialiser un projet Node.js :
npm init -y
  1. Installer les dépendances nécessaires :
npm install express express-session csurf helmet dotenv
  1. Vérifier que les fichiers suivants sont bien présents dans le dossier :
    • package.json (créé automatiquement)
    • node_modules/ (dossier contenant les bibliothèques installées)

Étape 2 : Configuration du serveur avec sessions sécurisées

L'application doit gérer des sessions sécurisées en appliquant les bonnes pratiques.

Instructions :

  1. Créer un fichier server.js et ajouter le code suivant :
require("dotenv").config();
const express = require("express");
const session = require("express-session");
const helmet = require("helmet");
const csrf = require("csurf");

const app = express();
app.use(helmet()); // Sécurisation des en-têtes HTTP

app.use(express.urlencoded({ extended: true })); // Permet de traiter les données des formulaires

app.use(session({
secret: process.env.SESSION_SECRET || "supersecretkey",
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true, // Protège contre XSS
secure: false, // À mettre sur true en production avec HTTPS
sameSite: "strict" // Protège contre CSRF
}
}));

const csrfProtection = csrf();
app.use(csrfProtection);

// Page d'accueil affichant le token CSRF
app.get("/", (req, res) => {
res.send(`<h1>Token CSRF généré : ${req.csrfToken()}</h1>`);
});

app.listen(3000, () => {
console.log("Serveur démarré sur http://localhost:3000");
});
  1. Créer un fichier .env et ajouter la ligne suivante :
SESSION_SECRET=une_clé_secrète_très_complexe
  1. Enregistrer les fichiers et exécuter le serveur :
node server.js
  1. Ouvrir un navigateur et aller sur http://localhost:3000/ pour voir le token CSRF généré.

Vérifier si :

  • Le serveur est correctement configuré avec Helmet pour sécuriser les en-têtes HTTP.
  • Les sessions sont protégées avec httpOnly, sameSite et un secret sécurisé.
  • Un token CSRF est généré et affiché sur la page d'accueil.

Étape 3 : Création d'un formulaire sécurisé contre CSRF

L'application doit contenir un formulaire de connexion protégé contre les attaques CSRF.

Instructions :

  1. Modifier server.js pour ajouter une route avec un formulaire de connexion :
app.get("/login", (req, res) => {
res.send(`
<form action="/login" method="POST">
<input type="text" name="username" placeholder="Nom d'utilisateur" required>
<input type="password" name="password" placeholder="Mot de passe" required>
<input type="hidden" name="_csrf" value="${req.csrfToken()}">
<button type="submit">Se connecter</button>
</form>
`);
});

app.post("/login", (req, res) => {
const { username, password } = req.body;

if (username === "admin" && password === "password123") {
req.session.user = username;
res.send("<h1>Connexion réussie</h1>");
} else {
res.send("<h1>Échec de l'authentification</h1>");
}
});
  1. Redémarrer le serveur et tester la connexion en visitant http://localhost:3000/login.

Vérifier si :

  • Un formulaire de connexion sécurisé est mis en place.
  • Le token CSRF est inclus dans le formulaire pour éviter les attaques CSRF.
  • L'authentification est basique mais fonctionnelle.

Étape 4 : Protection contre le Session Fixation

Après une connexion réussie, il est recommandé de regénérer l'identifiant de session pour éviter les attaques par fixation de session.

Instructions :

  1. Modifier la route /login pour régénérer l'identifiant de session après connexion :
app.post("/login", (req, res) => {
const { username, password } = req.body;

if (username === "admin" && password === "password123") {
req.session.regenerate((err) => {
if (err) {
return res.send("Erreur lors de la régénération de la session");
}
req.session.user = username;
res.send("<h1>Connexion réussie</h1>");
});
} else {
res.send("<h1>Échec de l'authentification</h1>");
}
});
  1. Redémarrer le serveur et tester la connexion.

Vérifier si :

  • La régénération de session empêche les attaques par fixation de session.
  • Après connexion, un nouvel identifiant de session est attribué à l'utilisateur.

Étape 5 : Déconnexion sécurisée

Il est important d'ajouter une fonction de déconnexion qui détruit la session de manière sécurisée.

Instructions :

  1. Ajouter une route /logout pour déconnecter l'utilisateur :
app.get("/logout", (req, res) => {
req.session.destroy((err) => {
if (err) {
return res.send("Erreur lors de la déconnexion");
}
res.send("<h1>Déconnexion réussie</h1>");
});
});
  1. Tester la déconnexion en visitant http://localhost:3000/logout.

Vérifier si :

  • La session est correctement détruite après déconnexion.
  • L'utilisateur ne peut plus accéder aux pages protégées après s'être déconnecté.

Conclusion

Ce TP a permis de mettre en place une gestion sécurisée des sessions en appliquant plusieurs bonnes pratiques :

  • Protection contre les attaques CSRF avec des tokens.
  • Sécurisation des cookies de session avec httpOnly, sameSite et secure.
  • Régénération de l'identifiant de session après connexion.
  • Déconnexion sécurisée pour éviter les abus.

Ces techniques sont essentielles pour garantir la sécurité des applications Web et protéger les utilisateurs contre les attaques courantes.