Introduction
Une application qui passe tous ses tests n’est pas pour autant une application sûre. Les tests vérifient que le code fait ce qu’on attend de lui, pas ce qu’il accepte de faire quand on lui envoie autre chose que ce qui était prévu.
C’est exactement l’angle mort que vient couvrir le DAST : au lieu de relire le code, on interroge l’application déployée depuis l’extérieur, comme le ferait quelqu’un qui n’a ni les sources, ni les accès, ni la documentation.
L’outil de référence sur ce besoin est ZAP Proxy, open source, gratuit et utilisable aussi bien à la main qu’en pipeline. Nous allons voir le principe du DAST et sa complémentarité avec l’analyse statique, la prise en main de ZAP et la différence entre un audit blackbox et greybox.
1. Comprendre le principe du DAST
Tester l’application en fonctionnement
Le DAST (Dynamic Application Security Testing) désigne l’analyse de sécurité d’une application en cours d’exécution. Le scanner ne lit jamais une ligne de code : il envoie des requêtes HTTP et déduit les problèmes des réponses qu’il reçoit.
Un scan se déroule toujours dans le même ordre :
- Exploration : un crawler parcourt l’application depuis l’URL de départ, suit les liens et teste les formulaires pour cartographier les URLs et les paramètres accessibles.
- Identification : le scanner déduit les technologies en place à partir des headers, des cookies et des pages d’erreur (serveur web, langage, framework).
- Sollicitation : il rejoue chaque requête en modifiant les paramètres, avec des charges conçues pour provoquer un comportement anormal.
- Analyse : le code de retour, le temps de réponse et le contenu renvoyé indiquent si l’application a réagi comme elle aurait dû.
- Restitution : chaque écart devient une alerte, classée par sévérité et par degré de confiance.
Ce que ce type d’analyse remonte le plus souvent, ce sont les injections SQL, les XSS, les en-têtes de sécurité manquants, les cookies mal configurés, les erreurs de configuration TLS ou CORS et les fuites d’informations techniques dans les réponses. Autrement dit, l’essentiel des catégories de l’OWASP Top 10, la référence qui classe les risques de sécurité applicative les plus répandus.
DAST et SAST : deux angles différents sur le même projet
Le SAST (Static Application Security Testing) fait exactement l’inverse : il lit le code sans jamais l’exécuter. Sur
nos projets Symfony, ce rôle est tenu par PHPStan pour l’analyse statique, par les tests
PHPUnit pour les comportements attendus et par composer audit pour les
CVE des dépendances.
| SAST | DAST | |
|---|---|---|
| Objet analysé | Le code source | L’application déployée |
| Moment | À chaque commit | Après déploiement |
| Visibilité | Tout le code, y compris le code mort | Uniquement ce qui est atteignable par le réseau |
| Preuve apportée | Un risque théorique dans le code | Un comportement observé sur l’application |
| Faux positifs | Fréquents sur les règles de sécurité | Moins nombreux, mais présents |
| Angle mort | Le contexte d’exécution et la configuration | Le code jamais atteint par le crawler |
Les deux ne se remplacent pas. Le SAST pourra par exemple détecter du code jamais appelé, le DAST ne le verra jamais mais pourra détecter qu’une apostrophe dans un paramètre fait remonter une erreur SQL en clair. Une vulnérabilité web observée en conditions réelles se priorise beaucoup plus facilement qu’un risque théorique.
Scan passif et scan actif
Les outils DAST ont souvent deux modes d’analyse qui influent sur le temps passé et sur la quantité d’éléments remontés.
Le scan passif se contente d’observer le trafic généré par l’exploration. Il n’envoie aucune requête offensive et ne modifie rien. C’est lui qui remonte les problèmes de configuration :
| Alerte ZAP | Ce qu’elle signale |
|---|---|
10038 Content Security Policy (CSP) Header Not Set | Aucune politique CSP, donc aucun garde-fou navigateur contre l’injection de scripts |
10020 Missing Anti-clickjacking Header | Ni X-Frame-Options ni directive frame-ancestors : la page est intégrable dans une iframe tierce |
10035 Strict-Transport-Security Header Not Set | Pas de HSTS, la première requête peut rester en HTTP |
10011 Cookie Without Secure Flag | Un cookie de session transmissible en clair |
10202 Absence of Anti-CSRF Tokens | Un formulaire sans jeton anti-CSRF |
10037 Server Leaks Information via X-Powered-By | La version de PHP ou du serveur annoncée à chaque réponse |
Le scan actif envoie de vraies charges d’attaque : injections, traversée de répertoires, manipulation de paramètres. C’est lui qui détecte les failles exploitables, mais son fonctionnement impacte la base de données de l’application, déclenche des traitements et génère de la charge. Il ne se lance jamais sur un environnement dont on ne maîtrise pas les données.
2. ZAP Proxy, l’outil DAST de référence
Comprendre le fonctionnement de ZAP
ZAP (Zed Attack Proxy) est un scanner de vulnérabilités web open source, gratuit et sans version payante. Son principe de base est celui d’un proxy : il s’intercale entre le client et l’application, observe tout le trafic qui passe, et peut le rejouer en le modifiant.

Autour de ce socle, il embarque tout ce qu’il faut pour un audit automatisé : un crawler classique, un crawler capable d’exécuter le JavaScript pour les applications à rendu client, un moteur de règles d’analyse et un générateur de rapports.
Prise en main avec l’interface graphique
L’application desktop est le meilleur point d’entrée pour comprendre ce que fait l’outil. Après un
Automated Scan sur une URL, l’écran se lit en trois zones : l’arborescence des URLs découvertes à gauche (3), les
alertes classées par sévérité en bas (5), et le détail requête / réponse à droite (4).

Chaque alerte affiche la requête exacte envoyée et la réponse obtenue, avec la portion de contenu qui a déclenché la règle, dans l’exemple ci-dessous l’exposition de la version d’Apache. Vous pouvez la rejouer telle quelle, modifier un paramètre et observer le résultat.

Nous utilisons ce mode de fonctionnement pour les prospects qui nous demandent un audit technique simple et ponctuel de l’état actuel de leur application.
Ce mode d’exploration peut aussi être utilisé pendant les développements, lors de l’ajout d’une nouvelle page ou d’une interface sensible. Il sert également après une alerte remontée par un scan automatisé en CI : on rejoue alors l’alerte en local pour mieux comprendre les conditions qui la déclenchent.
Usage en ligne de commande avec Docker
L’interface graphique reste un outil ponctuel.
Le vrai usage de ZAP est industrialisé, via son image Docker officielle et sa ligne de commande.
Comme pour l’audit de nos Dockerfile, la méthode à privilégier pour obtenir un rapport plus rapidement est d’utiliser l’image Docker et sa ligne de commande, qui permettent d’automatiser les sites, les URLs et la configuration à employer pour chaque scan.
Le comportement d’un scan lancé de cette façon est piloté par une config en yaml où l’on va définir des jobs,
chacun représentant une étape à exécuter. Pour chaque job, on peut définir les éléments suivants :
| Élément | Obligatoire | Rôle |
|---|---|---|
type | ✅ | Définit quelle opération ZAP doit effectuer |
name | ❌ | Donne un nom/identifiant lisible au job |
parameters | ❌ | Configure le comportement du job |
tests | ❌ | Définit des contrôles permettant de vérifier le résultat du job |
Parmi les type de job, on retrouve les deux modes mentionnés plus haut :
- passiveScan-config : permet de configurer le scanner passif de ZAP, qui analyse automatiquement les requêtes et réponses HTTP observées sans envoyer de requêtes d’attaque supplémentaires.
- activeScan permet à ZAP de rechercher activement des vulnérabilités via des policy en envoyant des requêtes spécialement conçues pour tester l’application.
La policy définit ce que le scan actif va réellement tester : quelles règles sont activées, et avec quel seuil
de confiance (threshold) avant de lever une alerte. ZAP applique par défaut une policy générique qui couvre
l’ensemble des règles connues.
Générer un rapport
Que ce soit depuis l’interface graphique ou via l’automatisation en ligne de commande, chaque scan permet de générer un rapport d’audit dans plusieurs formats (HTML pour la lecture, JSON pour l’exploitation programmatique…), afin de suivre dans le temps et de mieux analyser les alertes remontées par les différents scans.

3. Blackbox ou greybox : ce que le scan voit réellement
Le principe
En blackbox, l’auditeur ne dispose que de l’URL publique. Pas de compte, pas de documentation, pas d’accès au code : exactement la position d’un visiteur anonyme, donc celle de la très grande majorité des tentatives automatisées que subit une application exposée sur internet.
En greybox, il dispose en plus d’éléments internes : des comptes applicatifs avec différents rôles, la documentation de l’API, parfois le schéma de données. Le périmètre couvert change radicalement, puisque c’est derrière l’authentification que se trouve l’essentiel de la logique métier.
La question à trancher n’est donc pas de savoir laquelle est la meilleure, mais ce que l’on cherche à mesurer : la blackbox mesure ce qu’un inconnu peut atteindre, la greybox mesure ce qu’un utilisateur légitime peut détourner.
Le coût de mise en place d’un audit blackbox est minime comparé à un greybox : pas de compte à créer, pas de configuration d’authentification à maintenir. Pour autant, il apporte déjà une visibilité non négligeable sur ce qu’un inconnu peut voir de l’application. C’est pourquoi nous recommandons à nos clients de le mettre en place dès la première mise en production, sans attendre un audit plus poussé.
Comment cela se traduit dans ZAP
ZAP formalise cela dans la notion de contexte : un périmètre de scan nommé, avec ses URLs incluses, ses URLs exclues et sa profondeur de crawl. C’est le premier réglage à faire, avant toute autre configuration.
Un contexte greybox demande en plus de déclarer la méthode d’authentification, un ou plusieurs utilisateurs, les indicateurs qui permettent à ZAP de savoir s’il est toujours connecté, et surtout les URLs à exclure absolument : déconnexion, suppression de compte, envoi d’email, validation de paiement. Cette configuration se maintient dans le temps, au rythme des évolutions de l’application.
C’est précisément pour cette raison que nous industrialisons d’abord le mode blackbox. Il ne demande aucune préparation, aucun jeu de comptes à maintenir, on peut l’automatiser dans une scheduled pipeline de CI hebdomadaire ou mensuel et il répond à la question la plus urgente : qu’est-ce qu’un inconnu voit de notre application ? Le scan authentifié vient ensuite, sur les projets dont l’exposition le justifie.
Un rapport blackbox vierge ne dit pas “l’application est sûre”, il dit “rien n’a été trouvé sur les chemins atteints par le crawler”. C’est la limite structurelle de l’exercice, et elle doit être formulée telle quelle au client plutôt que laissée à son interprétation.
Applications à rendu client : ce qui change
Tout ce qui précède suppose un serveur qui renvoie du HTML complet, ce qui est le cas de nos projets Symfony rendus avec Twig. Sur une application à rendu client (React, Vue ou une stack Inertia), une partie des règles ne s’applique plus.
| Brique de ZAP | Sur une application à rendu client (Vue, SPA, …) |
|---|---|
Règles passives basées sur le HTML (10202 absence de jeton anti-CSRF, champs cachés, commentaires, formulaires) | Aveugles : le HTML servi n’est qu’une coquille, le contenu réel est construit par le navigateur |
Règles passives basées sur les en-têtes et les cookies (CSP, HSTS, SameSite, X-Content-Type-Options, fuites de version, SRI) | Parfaitement opérantes, le mode de rendu n’y change rien |
| Scanner actif (injection SQL, XSS, traversée de répertoires) | Parfaitement opérant, mais uniquement sur les requêtes qu’on lui a fait connaître |
Ce constat n’est pas une limite de ZAP mais du scanner passif standard. L’outil embarque aussi des règles de type Client Passive et un client spider, qui pilotent un vrai navigateur et analysent le DOM effectivement rendu. Sur ce type de projet, ce n’est plus une option mais le mode de fonctionnement à retenir.
La conséquence la plus importante porte sur le périmètre : la vraie surface d’attaque n’est plus constituée des pages mais des éventuels endpoints API appelés depuis le front. Comme ils ne sont liés depuis aucune page, le crawler classique ne les atteint jamais. Les déclarer explicitement ou importer la spécification OpenAPI de l’API devient alors le facteur déterminant de la couverture réelle du scan.
4. Automatiser le scan dans la CI
Sur quel environnement lancer le scan
En local, il n’y a aucune précaution à prendre. La stack Docker du projet tourne sur le poste du développeur, les données sont fausses et un scan actif ne peut rien casser d’irréversible. C’est l’environnement idéal pour apprendre l’outil et pour mettre au point la configuration du scan.
Pour les projets client, les scans ont lieu sur un environnement d’intégration de leur projet avec des données factices, sur le même hébergement Clever Cloud.
Il reproduit les conditions de la production sur ce qui compte pour un audit : mêmes versions de PHP et de MySQL, même configuration applicative, même chaîne de déploiement. Seules les données diffèrent, puisqu’il est alimenté par un jeu de données factices.
Cette séparation permet de garantir que les scans actifs ne vont pas polluer l’environnement de production.
Nos environnements d’intégration utilisent Maildev, qui intercepte tous les emails et ne les transmet jamais aux destinataires réels. Un scan qui déclenche cent fois un formulaire de contact ne génère donc aucun email parasite chez le client ni chez ses utilisateurs.
Automatiser le scan sur Intégration via la CI de GitLab
Sur nos projets, nous privilégions un seul type de scan automatisé via Docker dans notre CI plutôt que de maintenir passif et actif en parallèle : un scan actif en blackbox, qui englobe de fait tout ce que couvre le passif tout en offrant une couverture plus approfondie.
Cette automatisation se met en place via une pipeline programmée dans les Build > Pipeline Schedules de GitLab, avec une fréquence ajustée au besoin de chaque projet client.
5. Nos commandes prêtes à l’emploi dans notre standard-bundle
Nous avons regroupé nos bonnes pratiques ZAP Proxy dans notre standard-bundle, aux côtés des autres conventions (SAST, Tests, …).
Il embarque un fichier security.mk de règles de départ et les cibles de Makefile correspondantes, sur le
même modèle que les commandes make docker-scan de notre socle
symfony-docker :
make dast-blackbox-passive
make dast-blackbox-active
make dast-blackbox-ci
Tout tourne via l’image officielle Docker de ZAP : aucune installation sur le poste, la même version de ZAP pour tout le monde, les mêmes règles et le même format de rapport d’un projet à l’autre. Toute la configuration des sites cibles et des environnements est ensuite portée par un fichier de config JSON spécifique au projet et interprété par ces commandes.
6. Déploiement et mise en place avec le client
La partie technique est la plus rapide : les commandes existent, l’image Docker est la même partout, et seul le fichier de configuration JSON change d’un projet à l’autre. L’essentiel du travail est ailleurs, dans le cadrage. Voici les points à trancher avec le client avant le premier scan.
L’autorisation et l’environnement
Un scan actif envoie de vraies charges d’attaque. Même sur un environnement d’intégration, cela suppose un accord écrit du client avant le premier lancement. Si l’hébergement est infogéré par un tiers ou mutualisé, il faut également prévenir l’hébergeur : un scan ressemble beaucoup à une attaque vue depuis un WAF ou un système de détection, et peut déclencher un blocage d’IP en pleine pipeline.
Côté environnement, deux engagements sont à obtenir : que l’environnement d’intégration reste iso-production sur les versions et la configuration, et que son jeu de données factices soit maintenu. Un environnement laissé à l’abandon produit un rapport qui ne dit plus rien de la production.
Le périmètre à déclarer
C’est le seul élément réellement spécifique au projet, et il se construit avec le client :
- Les domaines et sous-domaines à couvrir. Chacun est un périmètre à part entière : une application, un back-office, une API et un service de téléchargement de fichiers n’exposent pas du tout la même surface.
- Les routes à exclure, sur lesquelles le client est le seul à pouvoir trancher : déconnexion, suppression, actions en masse, retours de paiement, webhooks.
- Les routes publiques non atteignables par le crawler. C’est le point le plus souvent oublié : une page accessible uniquement par un lien envoyé par email, un tunnel d’inscription annexe ou un formulaire de satisfaction ne sont liés depuis aucune page. Sans les déclarer explicitement, ils ne sont jamais scannés.
Le niveau d’alerte retenu
C’est le point de cadrage le plus structurant, et il recouvre en réalité deux décisions distinctes qu’il faut séparer : ce qui apparaît dans le rapport, et ce qui fait échouer la pipeline.
| Sévérité | Ce qu’on y trouve typiquement | Notre position par défaut |
|---|---|---|
| High | Injection SQL, exécution de code, traversée de répertoires | Bloquant : la pipeline échoue et l’alerte doit être traitée |
| Medium | CSP absente, clickjacking, cookies mal configurés, CORS trop permissif | Remontée dans le rapport (manuel et via CI), corrigée dans le lot courant de maintenance évolutive |
| Low | Version du serveur exposée, horodatages, commentaires suspects | Rapport manuel uniquement, arbitré au cas par cas |
| Informational | Observations de reconnaissance, sans risque direct | Rapport manuel uniquement pour être exhaustif sur ce qui a été scanné |
Ce réglage se discute. Sur une application exposée au grand public ou manipulant des données personnelles, on peut
mettre le niveau Medium comme sévérité minimale à traiter (donc en plus du High). À l’inverse, sur un outil
interne, on peut se contenter d’un rapport consultatif, sans exigence de correction immédiate.
Nous conseillons de fixer ce cadre au plus tôt dans le projet, tout en gardant à l’esprit qu’il peut évoluer au fur et à mesure que ce dernier le nécessite.
La fréquence et la durée
La pipeline programmée se règle selon le rythme réel du projet : hebdomadaire sur un projet en développement actif, mensuel sur une application stabilisée en maintenance.
La durée du scan est plafonnée par configuration, séparément pour l’exploration et pour le scan actif. Ces plafonds sont un arbitrage entre profondeur d’analyse et consommation de minutes CI, à poser avec le client selon la taille de l’application. Un plafond (durée max d’une étape de scan) qui est atteint n’est pas une erreur, mais il signifie que le scan a été interrompu avant d’avoir tout couvert : c’est une information à surveiller dans le temps.
Le traitement des résultats
Un scan qui tourne sans que personne ne lise ses rapports ne sert à rien. Trois points à acter :
- Qui reçoit le rapport et qui arbitre. Le rapport HTML est archivé en artefact de pipeline avec une durée de rétention définie, ce qui permet de comparer deux scans dans le temps.
- Comment les faux positifs sont traités. Ils existent, même en DAST. Une fois qualifiés avec le client, ils sont filtrés dans la configuration plutôt que ré-arbitrés à chaque scan.
- Ce qui devient un risque accepté. Certaines alertes ne seront pas corrigées, pour des raisons de coût ou de compatibilité. Elles doivent être tracées comme telles, et non laissées sans réponse dans le rapport.
Conclusion
Un scan DAST ne rend pas une application invulnérable. Ce qu’il offre, c’est la possibilité de rester informé de son exposition, même sans nouveau développement sur votre projet.
Pour l’équipe de développement, c’est une charge mentale en moins. Le scan tourne, il compare, il alerte. Personne n’a besoin de se souvenir de vérifier les cookies après une refonte du tunnel d’authentification, et les corrections se planifient dans le lot courant de maintenance évolutive au lieu d’arriver en urgence.
Pour la direction et les équipes métier, c’est la différence entre “on pense que c’est sécurisé” et une réponse datée, appuyée sur un rapport.
Liens utiles