Aller au contenu principal
own2pwn
appsec/sast-dast-cicd.tsx

Intégrer SAST et DAST dans sa CI/CD : le guide DevSecOps

Où placer le SAST (sur la PR) et le DAST (en staging) dans votre pipeline, comment brancher SARIF sur GitHub Code Scanning, et comment écrire un security gate qui bloque sans noyer les devs sous le bruit. Exemples GitHub Actions et GitLab CI inclus.

Maxime Jérôme··9 min de lecture

Vous connaissez la scène. Une faille passe en prod. La rétro commence, et quelqu'un finit par lâcher la phrase magique : « on aurait dû scanner ça avant ». Bien sûr qu'on aurait dû. Le problème, ce n'est presque jamais l'absence d'outils — c'est qu'ils tournent à côté du pipeline, dans un onglet que plus personne n'ouvre, au lieu de tourner dans le pipeline, là où ils peuvent réellement arrêter un déploiement.

Intégrer du SAST et du DAST dans sa CI/CD, ce n'est pas « ajouter une étape qui crache un rapport ». C'est répondre à trois questions précises : à quel moment chaque outil tourne, où atterrissent les résultats, et qu'est-ce qui décide de casser le build. On va répondre aux trois, avec du YAML qui existe vraiment et zéro flag inventé.

Drake refuse de scanner uniquement en local, approuve de scanner dans la CI
Le scanner sur votre laptop ne protège que votre laptop.

Le principe : shift-left, mais pas que

Le shift-left, c'est l'idée de pousser la sécurité le plus tôt possible dans le cycle de dev — sur le commit, sur la PR, avant que le code n'atteigne un environnement. Plus une faille est détectée tôt, moins elle coûte cher à corriger. C'est vrai, c'est documenté, et le secteur l'a largement adopté : selon Checkmarx, l'intégration du SAST directement dans les outils CI/CD existants des développeurs est aujourd'hui la norme.

Mais « shift-left » ne veut pas dire « tout à gauche ». Le SAST se déplace à gauche parce qu'il lit du code source — il n'a besoin de rien qui tourne. Le DAST, lui, a besoin d'une application déployée et fonctionnelle pour l'attaquer. Le coller sur chaque PR n'a tout simplement pas de sens. La bonne mentalité, c'est shift-left ce qui peut l'être, shift-right le reste.

La règle de placement, en une phrase
SAST = sur la PR (boîte blanche, instantané). DAST = en staging après déploiement (boîte noire, a besoin d'une appli qui tourne). Tout le reste découle de ça.

Où placer chaque outil dans le pipeline

Chaîne de montage robotisée dans une usine
Un pipeline CI/CD bien réglé : chaque commit passe sur la chaîne, contrôles de sécurité inclus.

Voici la topologie qui marche dans la vraie vie. Le SAST et les scans rapides (secrets, SCA) tournent tôt et bloquent la PR ; le DAST tourne après déploiement en staging, déclenché par le déploiement lui-même.

pipeline.txt
  Commit / Pull Request                Merge -> deploy staging
  ---------------------                ------------------------
        |                                       |
        v                                       v
  [ secrets scan ]  rapide                [ deploy staging ]
        |                                       |
        v                                       v
  [ SCA / deps   ]  rapide                [   DAST scan    ]  (appli qui tourne)
        |                                       |
        v                                       v
  [ SAST         ]  boite blanche         [ security gate  ]  high/critical ?
        |                                       |
        v                                  oui -+-> bloque la promotion prod
  [ security gate ] high/critical ?       non  -+-> promotion autorisee
        |
   oui -+-> FAIL la PR (bloque le merge)
   non  -+-> merge autorise
SAST + secrets + SCA bloquent la PR. Le DAST tourne en staging, après déploiement.

Notez qu'on ne lance pas le DAST sur chaque commit : c'est lent et ça exige une appli déployée. Snyk recommande une approche en couches : scans légers et ciblés au fil de l'eau, un DAST complet déclenché à chaque déploiement en staging, et un scan exhaustif planifié la nuit ou le week-end. Vous avez ainsi du feedback rapide sans transformer chaque push en pause café de quarante minutes.

Pourquoi pas tout en une seule étape ?

Parce que chaque outil regarde une chose différente, à un moment différent. Empiler les couches, c'est précisément ce qui réduit le bruit : croiser un finding SAST (« cette fonction est vulnérable ») avec un finding DAST (« et elle est réellement exploitable en runtime ») vous dit lesquelles corriger en premier. Un détail seul ment souvent ; deux détails qui concordent, beaucoup moins.

Brancher les résultats : SARIF + GitHub Code Scanning

Le piège classique : chaque outil a son propre format de rapport, et vous finissez avec quatre dashboards que personne ne consulte. La réponse s'appelle SARIF (Static Analysis Results Interchange Format), un format JSON standardisé que la plupart des scanners savent exporter. L'intérêt : un format unique que votre plateforme sait afficher au bon endroit.

Sur GitHub, ce bon endroit, c'est Code Scanning. Vous uploadez le SARIF, et les findings apparaissent directement dans l'onglet Security et en annotations sur la PR — là où le dev les voit sans changer de fenêtre. Voici l'étape officielle, telle qu'elle figure dans la documentation GitHub :

yaml
name: "Security scan"

on:
  pull_request:
  push:
    branches: [main]

jobs:
  sast:
    runs-on: ubuntu-latest
    permissions:
      security-events: write   # obligatoire pour publier dans Code Scanning
      actions: read
      contents: read
    steps:
      - name: Checkout repository
        uses: actions/checkout@v6

      # ... ici votre scanner SAST qui produit un fichier results.sarif ...

      - name: Upload SARIF file
        uses: github/codeql-action/upload-sarif@v4
        with:
          sarif_file: results.sarif
          category: my-analysis-tool
Le piège des permissions
Sans security-events: write, l'upload SARIF échoue silencieusement ou en 403, et vous passez l'après-midi à vous demander pourquoi l'onglet Security reste vide. C'est la première chose à vérifier.

Le paramètre category permet de distinguer plusieurs outils sur un même commit (un pour le SAST, un pour le SCA, etc.) sans que les résultats s'écrasent entre eux. Côté GitLab, l'équivalent passe par les rapports de sécurité natifs (artefacts reports:sast / reports:dast) affichés dans l'onglet Security & Compliance de la merge request.

Le security gate : où l'on décide de casser le build

On arrive au cœur du sujet. Un scan qui ne bloque jamais rien, c'est de la décoration. Le security gate (porte de sécurité), c'est la règle qui décide : ce finding fait-il échouer le pipeline, oui ou non ? Et c'est là que se joue toute la crédibilité de votre démarche.

Gandalf bloquant le passage, métaphore du security gate qui bloque la PR
Le security gate face à une PR qui embarque un secret hardcodé et trois injections SQL.

La tentation du débutant : « on bloque sur tout ». Résultat, la première PR échoue sur 4 000 findings dont 3 800 faux positifs, l'équipe désactive le gate dans la semaine, et vous voilà revenu au point de départ — sauf que maintenant tout le monde déteste la sécurité. Snyk le dit sans détour : il faut définir des seuils de sévérité clairs pour les échecs de build, en ne bloquant que sur le high et le critical, pour équilibrer sécurité et vélocité.

yaml
# Exemple GitLab CI : le gate ne casse le build que sur high/critical
sast_gate:
  stage: test
  script:
    - python check_findings.py report.sarif --fail-on high,critical
  # les findings low/medium sont remontes en rapport, sans bloquer
  allow_failure: false

dast:
  stage: deploy
  script:
    - run-dast --target https://staging.example.com --report dast.sarif
  rules:
    - if: '$CI_COMMIT_BRANCH == "staging"'   # DAST uniquement en staging

La logique du gate « adulte » tient en quelques principes :

  • Bloquer sur high/critical, remonter le reste. Les findings low/medium apparaissent dans le rapport et l'onglet Security, mais ne cassent pas le build. On les traite, on ne les ignore pas — mais ils n'ont pas droit de veto sur chaque PR.
  • Bloquer dur sur les secrets. Une clé API ou un mot de passe committé, c'est un échec immédiat, sévérité ou pas. Le coût d'une fuite de secret dépasse toujours le coût d'un build cassé.
  • Gérer les faux positifs proprement. Un fichier d'exceptions versionné (baseline / suppressions) plutôt qu'un gate désactivé. La différence entre une équipe mature et une équipe qui a juré sur la sécurité, c'est l'existence de ce fichier.
  • Différencier PR et déploiement. Le gate SAST bloque le merge ; le gate DAST bloque la promotion vers la prod. Deux portes, deux moments.
Roll safe
Can't break prod if the gate blocks the PR. C'est bête, c'est vrai, et c'est exactement pour ça qu'on met le gate avant le merge plutôt qu'après le déploiement.

Ne pas noyer les devs (sinon tout s'effondre)

Le plus gros risque d'un pipeline DevSecOps, ce n'est pas la faille qu'il rate. C'est l'alert fatigue : le moment où l'équipe arrête de lire les alertes parce qu'il y en a trop, et où elle finit par tout ignorer en bloc — y compris les vraies. Un scanner qui crie tout le temps, c'est un détecteur de fumée qu'on débranche.

Le chien dans la pièce en feu, le build passe au vert quand même
Build au vert, 4000 alertes ignorees, deux failles critiques en prod. This is fine.

Quelques garde-fous concrets contre le bruit :

  • Commencer petit. Le pattern recommandé par le secteur : d'abord le SAST sur les PR, puis le SCA/SBOM sur les builds, puis le DAST en staging. On ajoute une couche quand la précédente est sous contrôle, pas toutes le même jour.
  • Tuner pour votre stack. Les règles par défaut sont calibrées pour le plus grand dénominateur commun. Désactivez les familles de règles qui ne s'appliquent pas à votre archi, c'est le levier numéro un contre les faux positifs.
  • Différentiel sur les PR. Sur une PR, montrez les nouveaux findings introduits par le diff, pas la dette historique. Personne ne corrige 2 000 alertes héritées pour merger un fix de typo.
  • Croiser SAST et DAST. Comme vu plus haut, la corrélation entre les deux est ce qui sépare le « peut-être exploitable » du « exploitable, prioritaire, on corrige aujourd'hui ».

Quel outil, quand, et pour bloquer quoi

Le SAST et le DAST ne suffisent pas seuls : le secrets scanning et la SCA (analyse des dépendances) sont les deux compagnons indispensables, rapides et à fort rendement. Voici la table récapitulative.

OutilQuandVitesseBloque sur
Secrets scanCommit / PRInstantanéTout secret détecté
SCA / dépendancesPR / buildSecondesCVE high/critical exploitable
SASTPR (boîte blanche)Secondes à minutesNouveau finding high/critical
DASTStaging post-déploiementMinutes à heuresVuln runtime confirmée

Pour le détail des différences entre ces familles d'analyse — et ce que l'IA y change vraiment — voyez notre article pilier SAST, DAST, IAST : comparatif et ce que l'IA change.

Et concrètement, on fait comment chez own2pwn

Tout ce qui précède décrit le quoi. Le comment, c'est souvent là que ça coince : assembler, tuner et maintenir cette chaîne demande du temps que les équipes produit n'ont pas toujours. C'est exactement le problème que notre plateforme AI-Native AppSec (SecAI) résout : un SAST piloté par IA et un agent DAST autonome, avec une GitHub Action officielle, un export SARIF natif, une CLI pour GitLab et Jenkins, et un security gate configurable — exactement le câblage décrit dans cet article, prêt à brancher.

Et quand vous voulez aller au-delà de l'automatisé — valider une chaîne d'exploitation complexe, challenger une logique métier — c'est là qu'intervient l'humain. Voir notre approche du pentest automatisé par IA et notre pentest web whitebox pour les audits en profondeur.

À retenir
  • SAST sur la PR (boîte blanche, rapide), DAST en staging post-déploiement (a besoin d'une appli qui tourne). Plus secrets scan + SCA au plus tôt.
  • SARIF est le format pivot : uploadé dans GitHub Code Scanning, les findings apparaissent sur la PR et dans l'onglet Security (pensez à security-events: write).
  • Le security gate ne bloque que sur high/critical (et tout secret), remonte le reste. Un gate qui crie sur tout finit désactivé.
  • Commencer petit, tuner pour sa stack, afficher le différentiel sur les PR : c'est ça, éviter l'alert fatigue.

Articles liés