TP10 : DevSecOps « Shift Left » (secrets, SAST, dépendances, images, GitHub)

Le Shift Left consiste à déplacer les contrôles de sécurité vers la gauche du cycle de vie : sur le poste du développeur et dans la CI, plutôt qu’après la mise en production. Dans ce TP, vous analysez une application volontairement vulnérable avec les outils open source standard, vous les branchez dans GitHub Actions et dans Jenkins avec des quality gates, puis vous corrigez les failles.

⚠️ L’application vuln-app/ contient des failles réelles (injection SQL, injection de commande, XSS, dépendances vulnérables) et des secrets factices. Ne l’exposez jamais en dehors de la VM de lab.


Fichiers de départ : vuln-app.zip

1. Objectifs pédagogiques

À l’issue du TP, vous serez capable de :

  • associer chaque famille de risque à un outil : secrets (Gitleaks), SAST (Semgrep, CodeQL), SCA (npm audit, OWASP Dependency-Check, Dependabot), images et configuration (Trivy) ;
  • bloquer un secret avant le commit avec un hook pre-commit ;
  • lire un rapport et distinguer vrai positif, faux positif et risque accepté ;
  • configurer des quality gates qui font échouer un pipeline ;
  • sécuriser un workflow GitHub Actions (permissions minimales, Actions épinglées par SHA) et protéger la branche main.

Les images de cette page sont des schémas explicatifs, pas des captures d’écran.

2. Environnement du TP

  • VM de lab Ubuntu Server 26.04 avec Docker, Node.js 24, Git, pipx (sudo apt install -y pipx).

  • Copier vuln-app/ dans un nouveau dépôt GitHub public vuln-app (CodeQL et Dependabot sont gratuits sur les dépôts publics) :

    cd vuln-app && npm install && git init -b main && git add . && git commit -m "chore: import vuln-app"

    Ne poussez pas encore : la partie 2 commence par détecter les secrets avant qu’ils ne quittent le poste.

Tous les scanners sont lancés en conteneur : rien à installer.

Carte des scanners : quel outil pour quel risque Carte des scanners : quel outil pour quel risque

Famille Question posée Outils du TP
Secrets Un mot de passe ou un token est-il dans Git ? Gitleaks, push protection GitHub
SAST Mon code contient-il des motifs dangereux ? Semgrep, CodeQL
SCA Mes dépendances ont-elles des CVE connues ? npm audit, OWASP Dependency-Check, Dependabot
Image Les paquets de l’image ont-ils des CVE ? Trivy image
Config Le Dockerfile / l’IaC sont-ils mal configurés ? Trivy config

3. Partie 1 : Secrets avec Gitleaks

  • Analyser le dépôt (historique compris) :

    docker run --rm -v "$PWD:/repo" ghcr.io/gitleaks/gitleaks:latest git /repo --verbose
  • Noter les règles déclenchées (generic-api-key…), le fichier, la ligne et le commit.

  • Déplacer les secrets dans des variables d’environnement (process.env.JWT_SECRET…), créer un .env.example et ajouter .env au .gitignore.

  • Relancer Gitleaks : le secret est toujours détecté dans l’historique. Pourquoi ? Que faudrait-il faire pour un vrai secret ?

    Réponse attendue : révoquer le secret (le considérer comme compromis), puis éventuellement réécrire l’historique (git filter-repo). Supprimer le fichier ne suffit jamais.

  • Pour ce lab, repartir d’un historique propre (rm -rf .git && git init -b main …), puis créer un fichier .gitleaksignore vide pour documenter les futurs faux positifs.

4. Partie 2 : Hook pre-commit

  • Installer le hook fourni dans .pre-commit-config.yaml :

    pipx install pre-commit
    pre-commit autoupdate && pre-commit install
  • Ajouter une ligne const token = "Zk3P9xQm7Rt2Lw8Vn4Hb6Jc1Yd5Fs0Ga"; dans un fichier et tenter un git commit : il doit être refusé.

  • Retirer la ligne, commiter, puis pousser le dépôt sur GitHub.

5. Partie 3 : SAST avec Semgrep

  • Lancer Semgrep avec des règles JavaScript et OWASP :

    docker run --rm -v "$PWD:/src" semgrep/semgrep \
      semgrep scan --config p/javascript --config p/owasp-top-ten --error /src
  • Pour chaque résultat, compléter le tableau (à inclure dans votre rendu) :

Règle Fichier:ligne Vrai positif ? Correction
  • Corriger : requête paramétrée (db.all("… WHERE name = ?", [name])), execFile("ping", ["-c", "1", host]) avec validation de host, échappement HTML (ou res.json), expiresIn sur le JWT.
  • Relancer Semgrep jusqu’à obtenir 0 résultat bloquant. Si vous acceptez un résultat, justifiez-le par un commentaire // nosemgrep: <rule-id>.

6. Partie 4 : Dépendances et images

Shift left : contrôles du poste jusqu’à la quality gate Shift left : contrôles du poste jusqu’à la quality gate

  • Analyser les dépendances :

    npm audit
    npm audit --audit-level=high; echo "code retour : $?"
  • Lancer OWASP Dependency-Check (le premier lancement télécharge la base NVD et peut prendre du temps ; une clé d’API NVD gratuite l’accélère) :

    docker run --rm -v "$PWD:/src" -v dc-data:/usr/share/dependency-check/data \
      owasp/dependency-check:latest --scan /src --format HTML --out /src/reports \
      --project vuln-app # ajouter --nvdApiKey <clé> si vous en avez une
  • Comparer les résultats de npm audit et de Dependency-Check : mêmes CVE ? même gravité ?

  • Construire l’image et l’analyser avec Trivy :

    docker build -t vuln-app:1 .
    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock aquasec/trivy:latest \
      image --severity HIGH,CRITICAL vuln-app:1
    docker run --rm -v "$PWD:/src" aquasec/trivy:latest config /src
  • Corriger : mettre à jour les dépendances (npm audit fix, puis à la main si nécessaire), réécrire le Dockerfile (image node:24-alpine, multi-stage, USER node, aucun secret dans ENV), relancer les trois outils et noter le nombre de vulnérabilités avant / après.

7. Partie 5 : GitHub (CodeQL, Dependabot, workflow sécurisé)

  • Settings → Code security : activer Dependency graph, Dependabot alerts, Dependabot security updates, Secret scanning et Push protection.
  • Ajouter un fichier .github/dependabot.yml (écosystèmes npm et github-actions, fréquence hebdomadaire) et observer les Pull Requests ouvertes par Dependabot.
  • Activer CodeQL (Code scanning → Set up → Default). Comparer ses alertes avec celles de Semgrep :
Faille Semgrep CodeQL
Injection SQL
Injection de commande
XSS
  • Compléter le workflow .github/workflows/security.yml :

    • permissions: contents: read au niveau du workflow ; security-events: write uniquement là où c’est nécessaire ;
    • Gitleaks, Semgrep (avec export SARIF dans l’onglet Security), npm audit, Trivy image et config ;
    • chaque Action tierce épinglée par SHA complet (uses: owner/action@<sha> # vX.Y.Z).

    Pourquoi épingler par SHA ? Un tag (v4) peut être déplacé vers un code malveillant si le dépôt de l’Action est compromis. Un SHA de commit est immuable. Dependabot (github-actions) se charge ensuite de proposer les mises à jour.

  • Créer une règle de protection (ruleset) sur main : Pull Request obligatoire, 1 approbation, checks secrets, sast, dependencies et image obligatoires, push direct interdit.

  • Ouvrir une PR qui réintroduit l’injection SQL : elle doit être bloquée.

8. Partie 6 : Quality gates dans Jenkins

  • Ajouter au Jenkinsfile du TP9 un stage Security exécutant en parallèle Gitleaks, Semgrep et npm audit, puis un stage Image scan (Trivy, --exit-code 1 --severity CRITICAL) après le build.
  • Archiver les rapports (archiveArtifacts 'reports/**').
  • Démontrer un pipeline rouge (faille réintroduite) puis vert (faille corrigée).

Défi

  1. Écrire une règle Semgrep personnalisée qui interdit console.log(req.body) (fuite de données personnelles dans les logs) et l’ajouter à la CI.
  2. Créer un fichier .trivyignore pour une CVE sans correctif disponible, avec une date d’expiration et une justification, et expliquer la différence entre « ignorer » et « accepter un risque ».

9. Livrables

Captures à déposer dans captures/ :

Fichier Contenu attendu
gitleaks.png Secrets détectés par Gitleaks
pre-commit-blocked.png Commit refusé par le hook
semgrep-before-after.png Résultats Semgrep avant / après correction
trivy-before-after.png Vulnérabilités de l’image avant / après
dependabot-pr.png Pull Request ouverte par Dependabot
codeql-alerts.png Alertes CodeQL dans l’onglet Security
pr-blocked.png PR bloquée par un check de sécurité obligatoire
jenkins-security.png Pipeline Jenkins rouge puis vert

Ainsi que : le code corrigé, security.yml, dependabot.yml, le Jenkinsfile et les tableaux remplis.