Aucun résultat pour cette recherche.
OWASP ZAP (Zaproxy) - Guide Complet de A à Z¶
Table des matières¶
- Introduction
- Installation et Configuration
- Interface et Concepts Fondamentaux
- Proxy et Interception
- Scan Passif et Actif
- Spider et Découverte
- Fuzzing et Tests Avancés
- Automatisation et Scripting
- API Testing
- Authentication et Session Management
- Reporting et Documentation
- ZAP en Mode Headless/CLI
- Intégration CI/CD
- Extensions et Add-ons
- Cas Pratiques et Scénarios Réels
- Bonnes Pratiques et Éthique
Introduction¶
Qu’est-ce qu’OWASP ZAP ?¶
OWASP Zed Attack Proxy (ZAP) est un scanner de vulnérabilités web open-source et gratuit. C’est l’un des projets phares de l’OWASP (Open Web Application Security Project).
Caractéristiques principales¶
- Proxy intercepteur : Capture et modifie le trafic HTTP/HTTPS
- Scanner automatique : Détection passive et active des vulnérabilités
- Spider/Crawler : Exploration automatique des applications web
- Fuzzer : Tests de robustesse avec données malformées
- API : Support REST, SOAP, GraphQL
- Extensible : Marketplace d’add-ons et scripts personnalisés
- Multi-plateforme : Windows, Linux, macOS, Docker
Pourquoi utiliser ZAP ?¶
✅ Avantages : - Gratuit et open-source - Facile à utiliser (GUI + CLI) - Excellent pour l’apprentissage - Intégration CI/CD native - Communauté active - Mises à jour fréquentes
ZAP vs Burp Suite¶
| Critère | ZAP | Burp Suite |
|---|---|---|
| Prix | Gratuit | Gratuit (limité) / Payant |
| Open Source | ✅ Oui | ❌ Non |
| Interface | Java Swing | Java Swing |
| Automatisation | ✅ Excellente | ✅ Excellente (Pro) |
| Intégration CI/CD | ✅ Native | ⚠️ Limitée (Free) |
| Extensions | ✅ Marketplace | ✅ BApp Store |
| Courbe d’apprentissage | Moyenne | Moyenne |
| Support API | ✅ Oui | ✅ Oui |
Installation et Configuration¶
Installation sur Linux (Debian/Ubuntu)¶
# Méthode 1 : Via Snap (recommandé)
sudo snap install zaproxy --classic
# Méthode 2 : Téléchargement direct
wget https://github.com/zaproxy/zaproxy/releases/download/v2.14.0/ZAP_2.14.0_Linux.tar.gz
tar -xvf ZAP_2.14.0_Linux.tar.gz
cd ZAP_2.14.0
./zap.sh
# Méthode 3 : Via package manager (peut être obsolète)
sudo apt update
sudo apt install zaproxy
# Vérification de l'installation
zap.sh -version
Installation sur macOS¶
# Méthode 1 : Homebrew
brew install --cask owasp-zap
# Méthode 2 : Téléchargement depuis le site officiel
# Télécharger depuis https://www.zaproxy.org/download/
# Ouvrir le fichier .dmg et glisser dans Applications
# Lancer ZAP
open /Applications/OWASP\ ZAP.app
# Ou via terminal
/Applications/OWASP\ ZAP.app/Contents/MacOS/OWASP\ ZAP.sh
Installation sur Windows¶
# Méthode 1 : Chocolatey
choco install zap
# Méthode 2 : Téléchargement installeur
# Télécharger ZAP_2.14.0_windows.exe depuis le site officiel
# Exécuter l'installeur
# Méthode 3 : Version portable
# Télécharger ZAP_2.14.0_windows.zip
# Extraire et exécuter zap.bat
# Lancer ZAP
"C:\Program Files\OWASP\Zed Attack Proxy\zap.bat"
Installation via Docker¶
# Pull de l'image officielle
docker pull zaproxy/zap-stable
# Lancer ZAP en mode daemon (headless)
docker run -u zap -p 8080:8080 -i zaproxy/zap-stable zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.addrs.addr.name=.* -config api.addrs.addr.regex=true
# Lancer ZAP avec interface GUI (Linux avec X11)
xhost +local:docker
docker run -u zap -p 8080:8080 -e DISPLAY=$DISPLAY -v /tmp/.X11-unix:/tmp/.X11-unix zaproxy/zap-stable zap.sh
# Version weekly (dernières features)
docker pull zaproxy/zap-weekly
Configuration initiale¶
Premier lancement¶
# Lancer ZAP
zap.sh # Linux/macOS
zap.bat # Windows
Au premier lancement, vous verrez :
-
Session Persistence : - “Do you want to persist the ZAP session?” - Recommandation : Choisir “Yes, I want to persist this session”
-
Quick Start : - Automated Scan - Manual Explore - Choisir selon votre besoin
Configuration du proxy¶
Paramètres par défaut :
- Host : localhost ou 127.0.0.1
- Port : 8080
Pour changer le port : 1. Tools → Options → Local Proxies 2. Modifier “Address” et “Port” 3. Cliquer “OK”
# Ou via ligne de commande
zap.sh -port 8081
Configuration du certificat SSL¶
ZAP génère son propre certificat CA pour intercepter HTTPS.
Installation du certificat :
- Dans ZAP : Tools → Options → Dynamic SSL Certificates
- Cliquer “Save”
- Enregistrer
owasp_zap_root_ca.cer
Installation dans le navigateur (Firefox) :
1. Firefox → Settings → Privacy & Security
2. Certificates → View Certificates
3. Authorities → Import
4. Sélectionner owasp_zap_root_ca.cer
5. Cocher "Trust this CA to identify websites"
Installation dans le navigateur (Chrome/Edge) :
1. Settings → Privacy and security → Security
2. Manage certificates → Authorities → Import
3. Sélectionner owasp_zap_root_ca.cer
4. Cocher "Trust this certificate for identifying websites"
Installation système (Linux) :
# Copier le certificat
sudo cp owasp_zap_root_ca.cer /usr/local/share/ca-certificates/zap.crt
# Mettre à jour les certificats
sudo update-ca-certificates
Installation système (macOS) :
# Ajouter au keychain
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain owasp_zap_root_ca.cer
Configuration du navigateur comme proxy¶
Firefox (manuel) :
1. Settings → General → Network Settings
2. Cliquer "Settings"
3. Sélectionner "Manual proxy configuration"
4. HTTP Proxy: localhost, Port: 8080
5. Cocher "Also use this proxy for HTTPS"
6. Cliquer "OK"
Chrome/Edge (via extension) :
1. Installer "FoxyProxy" ou "Proxy SwitchyOmega"
2. Configurer un profil :
- HTTP: localhost:8080
- HTTPS: localhost:8080
3. Activer le profil
Configuration système (Linux) :
# Temporary
export http_proxy=http://localhost:8080
export https_proxy=http://localhost:8080
# Ajouter au ~/.bashrc pour permanent
echo 'export http_proxy=http://localhost:8080' >> ~/.bashrc
echo 'export https_proxy=http://localhost:8080' >> ~/.bashrc
Interface et Concepts Fondamentaux¶
Vue d’ensemble de l’interface¶
┌─────────────────────────────────────────────────────────────┐
│ Menu Bar: File, Edit, View, Analyze, Report, Tools, Help │
├─────────────────────────────────────────────────────────────┤
│ Top Toolbar: New Session, Spider, Active Scan, Attack... │
├──────────────┬──────────────────────────────────────────────┤
│ │ │
│ Sites │ Work Area (Tabs) │
│ Tree │ - Quick Start │
│ │ - Request/Response │
│ [+] Sites │ - Spider │
│ [+] http │ - Active Scan │
│ GET │ - Fuzzer │
│ POST │ - etc. │
│ │ │
├──────────────┴──────────────────────────────────────────────┤
│ Bottom Tabs: │
│ History | Search | Alerts | Output | Breakpoints │
└─────────────────────────────────────────────────────────────┘
Panneau Sites Tree¶
Affiche l’arborescence des sites explorés.
Structure :
Sites
└── http://exemple.com
├── GET:index.php
├── GET:about.php
├── POST:login.php
└── GET:admin
└── GET:dashboard.php
Codes couleur : - 🔴 Rouge : Alerte haute sévérité - 🟠 Orange : Alerte moyenne - 🟡 Jaune : Alerte basse - 🔵 Bleu : Information - ⚪ Blanc : Pas d’alerte
Panneau History¶
Liste toutes les requêtes/réponses interceptées.
Colonnes importantes : - # : Numéro de séquence - Method : GET, POST, PUT, DELETE, etc. - URL : URL complète - Code : Code HTTP (200, 404, 500, etc.) - Reason : OK, Not Found, Internal Server Error - RTT : Round Trip Time (temps de réponse) - Size : Taille de la réponse - Flags : Indicateurs (cookies, scripts, etc.)
Filtres disponibles :
Clic droit → Filter
- Show only in scope
- Show only with alerts
- Show only POST requests
- Etc.
Panneau Alerts¶
Affiche toutes les vulnérabilités détectées.
Niveaux de sévérité : - High : Critique, exploitation immédiate possible - Medium : Importante, nécessite attention - Low : Mineure, amélioration recommandée - Informational : Information, pas de risque direct
Informations par alerte : - Description - URL(s) affectée(s) - Paramètre vulnérable - Preuve (payload utilisé) - Solution recommandée - Références (CWE, OWASP, etc.)
Concepts clés¶
1. Context¶
Un contexte définit le périmètre de test.
Créer un contexte :
1. Clic droit sur un site → Include in Context → New Context
2. Nommer le contexte (ex: "MonAppWeb")
3. Définir les URLs incluses/exclues
4. Configurer l'authentification si nécessaire
Exemple de regex d’inclusion :
https://exemple\.com/app/.*
Exemple de regex d’exclusion :
https://exemple\.com/app/logout.*
https://exemple\.com/app/static/.*
2. Scope¶
Le scope limite les tests aux URLs pertinentes.
Ajouter au scope :
Clic droit sur URL → Include in Scope
Avantages : - Évite les tests hors périmètre - Optimise les performances - Respecte le périmètre autorisé
3. Sessions¶
Une session sauvegarde tout votre travail.
Sauvegarder une session :
File → Persist Session
Ou : Ctrl+S
Charger une session :
File → Open Session
Format : Fichier .session contenant :
- Sites explorés
- Historique des requêtes
- Alertes détectées
- Configuration
4. Breakpoints¶
Les breakpoints permettent d’intercepter et modifier les requêtes/réponses.
Activer les breakpoints :
1. Bouton "Break" dans la toolbar (icône pause)
2. Ou : Ctrl+B
Types de breakpoints : - Break on all requests - Break on all responses - Break on specific URL pattern - Break on specific HTTP method
Utilisation :
1. Activer le breakpoint
2. Naviguer dans l'application
3. Modifier la requête/réponse dans l'éditeur
4. Cliquer "Continue" ou "Drop"
Proxy et Interception¶
Configuration basique du proxy¶
Vérifier que le proxy fonctionne :
- Configurer votre navigateur pour utiliser
localhost:8080 - Visiter
http://example.com - Observer le trafic dans ZAP (onglet History)
Test rapide :
# Via curl
curl -x http://localhost:8080 http://example.com
# Via wget
wget -e use_proxy=yes -e http_proxy=localhost:8080 http://example.com
Interception manuelle¶
Scénario : Modifier une requête de connexion
-
Activer l’interception :
Toolbar → Bouton "Break" (vert → rouge) -
Naviguer vers le formulaire de login :
http://exemple.com/login.php -
Soumettre le formulaire :
Username: test Password: password123 -
La requête est interceptée dans ZAP : ```http POST /login.php HTTP/1.1 Host: exemple.com Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSID=abc123
username=test&password=password123 ```
- Modifier la requête : ```http POST /login.php HTTP/1.1 Host: exemple.com Content-Type: application/x-www-form-urlencoded Cookie: PHPSESSID=abc123
username=admin&password=admin’ OR ‘1’=‘1 ```
- Envoyer la requête modifiée :
Bouton "Continue" ou "Submit and continue to break"
Interception de réponses¶
Activer l’interception de réponses :
Break → Break on all responses
Exemple : Modifier une réponse JSON
Réponse originale :
{
"user": "john",
"role": "user",
"admin": false
}
Réponse modifiée :
{
"user": "john",
"role": "admin",
"admin": true
}
Filtres d’interception avancés¶
Intercepter uniquement certaines requêtes :
- Tools → Options → Breakpoints
- Add Custom HTTP Breakpoint
- Configurer :
URL String Match: /api/ Method: POST Request/Response: Request
Exemples de filtres :
# Intercepter tous les POST vers /api/
URL: /api/.*
Method: POST
# Intercepter les réponses 302 (redirections)
Status Code: 302
Response: Checked
# Intercepter les requêtes avec un cookie spécifique
Header (name): Cookie
Header (value): admin=true
Resend/Replay¶
Renvoyer une requête modifiée :
- Sélectionner une requête dans History
- Clic droit → Open/Resend with Request Editor
- Modifier la requête
- Cliquer “Send”
Exemple : Test d’injection SQL manuelle
Requête originale :
GET /product.php?id=42 HTTP/1.1
Host: exemple.com
Requête modifiée :
GET /product.php?id=42' HTTP/1.1
Host: exemple.com
Observer la réponse pour détecter une erreur SQL :
Error: You have an error in your SQL syntax near ''42'' at line 1
Manual Request Editor¶
Envoyer une requête arbitraire :
Tools → Manual Request Editor
Ou : Ctrl+M
Exemple : Test d’API REST
POST /api/v1/users HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"username": "newuser",
"email": "test@exemple.com",
"role": "admin"
}
HUD (Heads Up Display)¶
ZAP HUD est une interface moderne overlay dans le navigateur.
Activer le HUD :
1. Tools → Options → HUD
2. Cocher "Enable when using the ZAP Desktop"
3. Lancer le HUD : Quick Start → Manual Explore → Launch Browser
Fonctionnalités HUD : - Attack Modes : Safe, Protected, Standard, Attack - Scope : Ajouter rapidement au scope - Alerts : Voir les alertes en temps réel - Spider : Lancer le spider sur la page courante - Active Scan : Scan actif rapide - Break : Activer/désactiver l’interception
Modes d’attaque :
Safe → Pas de requêtes potentiellement dangereuses
Protected → Uniquement sur les URLs en scope
Standard → Toutes les requêtes autorisées
Attack → Mode agressif, toutes attaques activées
Scan Passif et Actif¶
Scan Passif¶
Le scan passif analyse le trafic sans envoyer de nouvelles requêtes.
Caractéristiques : - ✅ Sans risque - ✅ Pas d’impact sur l’application - ✅ Toujours activé par défaut - ❌ Détection limitée
Activer/Désactiver :
Toolbar → Enable/Disable Passive Scan (icône bouclier)
Types de vulnérabilités détectées :
-
Informations sensibles exposées - Commentaires HTML avec infos - Messages d’erreur détaillés - Divulgation de versions
-
Headers de sécurité manquants - X-Frame-Options - X-Content-Type-Options - Content-Security-Policy - Strict-Transport-Security
-
Cookies non sécurisés - Absence de flag Secure - Absence de flag HttpOnly - Absence de flag SameSite
-
Autres : - Mixed Content (HTTP dans HTTPS) - Scripts obsolètes - Autocomplete activé sur champs sensibles
Exemple d’alerte passive :
Alert: Cookie Without Secure Flag
Risk Level: Low
Confidence: Medium
Description:
A cookie has been set without the secure flag, which means that the cookie can be accessed via unencrypted connections.
URL: https://exemple.com/login
Parameter: sessionid
Evidence: Set-Cookie: sessionid=abc123; Path=/; HttpOnly
Solution:
Whenever a cookie contains sensitive information or is a session token, then it should always be passed using an encrypted channel. Ensure that the secure flag is set for cookies containing such sensitive information.
Reference:
https://owasp.org/www-community/controls/SecureCookieAttribute
CWE-614
Scan Actif¶
Le scan actif envoie des payloads malveillants pour détecter les vulnérabilités.
⚠️ ATTENTION : - Peut modifier des données - Peut causer des DoS - Peut déclencher des alertes WAF/IDS - Nécessite une autorisation écrite
Lancer un scan actif :
Méthode 1 : Via Quick Start
1. Quick Start → Automated Scan
2. Entrer l'URL : http://exemple.com
3. Cliquer "Attack"
Méthode 2 : Via Sites Tree
1. Clic droit sur un site/dossier
2. Attack → Active Scan
3. Configurer les options
4. Cliquer "Start Scan"
Méthode 3 : Via Menu
Tools → Active Scan
Configuration du scan actif :
1. Clic droit sur site → Attack → Active Scan
2. Onglet "Policy"
3. Sélectionner ou créer une politique de scan
Politiques de scan prédéfinies :
| Politique | Description | Temps | Risque |
|---|---|---|---|
| Default | Équilibré | Moyen | Moyen |
| Light | Tests basiques | Rapide | Faible |
| Medium | Tests standards | Moyen | Moyen |
| Heavy | Tests approfondis | Lent | Élevé |
| SQLi | Focus injection SQL | Rapide | Moyen |
| XSS | Focus XSS | Rapide | Moyen |
Personnaliser une politique :
1. Analyze → Scan Policy Manager
2. Cliquer "Add"
3. Nommer la politique : "Custom Policy"
4. Configurer les seuils :
- Threshold : Off, Low, Medium, High
- Strength : Low, Medium, High, Insane
Exemple de configuration :
Vulnerability: SQL Injection
Threshold: Medium (lance le test si probabilité moyenne)
Strength: High (teste beaucoup de variantes)
Vulnerability: Path Traversal
Threshold: Low (toujours lancer)
Strength: Medium
Vulnerability: CRLF Injection
Threshold: Off (désactivé)
Types de vulnérabilités détectées (scan actif) :
-
Injection - SQL Injection - OS Command Injection - LDAP Injection - XPath Injection - SSTI (Server-Side Template Injection)
-
XSS (Cross-Site Scripting) - Reflected XSS - Stored XSS - DOM-based XSS
-
Autres - Path Traversal - Remote File Inclusion - CSRF (Cross-Site Request Forgery) - XXE (XML External Entity) - SSRF (Server-Side Request Forgery) - Insecure Deserialization
Exemple d’alerte active :
Alert: SQL Injection
Risk Level: High
Confidence: Medium
Description:
SQL injection may be possible.
URL: http://exemple.com/product.php?id=42
Parameter: id
Attack: 42' AND '1'='1' --
Evidence: JDBC error: You have an error in your SQL syntax
Solution:
Do not trust client side input, even if there is client side validation. Use parameterized queries (prepared statements) for all database queries.
Original Value: 42
Attack Value: 42' AND '1'='1' --
Reference:
https://owasp.org/www-community/attacks/SQL_Injection
CWE-89
WASC-19
Optimisation des scans¶
Limiter le nombre de threads :
Tools → Options → Active Scan
Host per Scan: 2 (défaut: 2)
Concurrent Scans: 2 (défaut: 2)
Ajuster les timeouts :
Tools → Options → Connection
Timeout (in seconds): 20
Exclure certaines technologies :
1. Analyze → Scan Policy Manager
2. Sélectionner votre politique
3. Technology → Exclude
- Exclure les technologies non utilisées
- Ex: MySQL si l'app utilise PostgreSQL
Limiter le scan à certains types :
Clic droit → Attack → Active Scan
Onglet "Policy" → Show Advanced Options
Cocher uniquement :
- Injection
- XSS
- Path Traversal
Spider et Découverte¶
Spider Traditionnel¶
Le spider explore l’application en suivant les liens HTML.
Lancer le spider :
Méthode 1 : Via Quick Start
Quick Start → Manual Explore
Entrer URL → Launch Browser
Toolbar → Spider (icône araignée)
Méthode 2 : Via Sites Tree
Clic droit sur site → Attack → Spider
Méthode 3 : Via Menu
Tools → Spider
Configuration du spider :
Tools → Options → Spider
Paramètres importants :
| Paramètre | Description | Valeur recommandée |
|---|---|---|
| Maximum Depth | Profondeur max | 5-10 |
| Maximum Children | Liens max par page | 0 (illimité) |
| Maximum Duration | Durée max (minutes) | 0 (illimité) |
| Thread Count | Nombre de threads | 2-5 |
| Parse Comments | Parser les commentaires HTML | ✅ |
| Parse robots.txt | Respecter robots.txt | ❌ (en pentest) |
| Parse sitemap.xml | Parser sitemap.xml | ✅ |
| POST Form | Soumettre les formulaires | ✅ |
| Process Form | Traiter les formulaires | ✅ |
Exemple de configuration avancée :
1. Tools → Options → Spider
2. Onglet "Advanced"
3. Configurer :
- Maximum Depth to Crawl: 5
- Number of Threads: 3
- Parse Comments: checked
- Parse Git metadata: checked
- Parse SVN metadata: checked
- Post Form: checked
Exclure des URLs du spider :
Tools → Options → Spider
Onglet "Advanced" → Excluded URLs
Ajouter regex :
.*logout.*
.*delete.*
.*admin/remove/.*
AJAX Spider¶
Le spider AJAX utilise un navigateur réel pour explorer les applications JavaScript/AJAX.
Quand utiliser l’AJAX Spider : - Applications Single Page (SPA) - Sites utilisant massivement JavaScript - AJAX pour charger du contenu - React, Angular, Vue.js applications
Lancer l’AJAX Spider :
Clic droit sur site → Attack → AJAX Spider
Configuration AJAX Spider :
Tools → Options → AJAX Spider
Paramètres importants :
| Paramètre | Description | Valeur |
|---|---|---|
| Browser | Navigateur utilisé | Firefox Headless |
| Max Duration | Durée max (minutes) | 60 |
| Max Crawl Depth | Profondeur max | 10 |
| Number of Browsers | Instances parallèles | 1 |
| Max Crawl States | États max explorés | 0 (illimité) |
| Click Elements | Cliquer sur éléments | ✅ |
| Random Inputs | Valeurs aléatoires forms | ✅ |
Exemple complet : Spider une SPA
1. Ajouter le site au scope :
Clic droit → Include in Scope
2. Lancer le spider traditionnel d'abord :
Clic droit → Attack → Spider
(pour découvrir les ressources statiques)
3. Lancer l'AJAX Spider :
Clic droit → Attack → AJAX Spider
4. Observer les nouveaux liens dans Sites Tree
5. Analyser avec scan passif puis actif
Sortie exemple :
Sites découvertes après spider traditionnel :
└── http://spa.exemple.com
├── GET:/ (index.html)
├── GET:/css/app.css
├── GET:/js/app.js
└── GET:/js/vendor.js
Sites découvertes après AJAX spider :
└── http://spa.exemple.com
├── GET:/ (index.html)
├── GET:/css/app.css
├── GET:/js/app.js
├── GET:/js/vendor.js
├── GET:/api/users
├── POST:/api/login
├── GET:/api/products
├── GET:/dashboard
└── GET:/settings
Forced Browse / Directory Busting¶
Découvre les fichiers et répertoires cachés.
Installer l’add-on :
1. Manage Add-ons (icône puzzle)
2. Marketplace
3. Rechercher "Forced Browse"
4. Installer
Lancer Forced Browse :
Clic droit sur site → Attack → Forced Browse
Configuration :
1. Select list: Common directories (default)
2. Liste personnalisée disponibles :
- Common directories
- Common files
- SVN files
- Git files
- Admin pages
- Backup files
Liste personnalisée :
Créer un fichier custom-dirs.txt :
/admin
/administrator
/backup
/config
/.git
/.svn
/test
/dev
/api
/api/v1
/api/v2
/.env
/web.config
/config.php
/database.sql
/backup.zip
Utiliser la liste :
Forced Browse → File → Load → custom-dirs.txt
Exemple de résultats :
✅ Found: http://exemple.com/admin (200 OK)
✅ Found: http://exemple.com/.git/config (200 OK)
✅ Found: http://exemple.com/backup.zip (200 OK)
❌ Not Found: http://exemple.com/test (404)
❌ Not Found: http://exemple.com/dev (403 Forbidden)
Fuzzing et Tests Avancés¶
Fuzzer intégré¶
Le fuzzer permet de tester une application avec des données variées et malformées.
Lancer le fuzzer :
- Sélectionner une requête dans History
- Clic droit → Attack → Fuzz
- Sélectionner le paramètre à fuzzer
- Configurer les payloads
Exemple pratique : Fuzzer un paramètre
Requête de base :
GET /search.php?q=test HTTP/1.1
Host: exemple.com
Étapes :
- Sélectionner “test” dans la requête
- Clic droit → Fuzz
- Bouton “Add”
- Choisir le type de payload
Types de payloads disponibles :
| Type | Description | Exemple |
|---|---|---|
| File | Depuis un fichier | wordlist.txt |
| File Fuzzers | Listes intégrées | XSS, SQLi, LFI |
| Strings | Liste personnalisée | Manual input |
| Regex | Génération par regex | [a-z]{5} |
| Numberzz | Séquence numérique | 1-1000 |
| Scripts | Script personnalisé | JavaScript/Python |
Exemple 1 : Fuzzing XSS
1. Sélectionner le paramètre à tester
2. Add → File Fuzzers → XSS
3. Payloads XSS chargés (100+ variantes)
4. Start Fuzzer
Payloads XSS utilisés :
<script>alert('XSS')</script>
<img src=x onerror=alert('XSS')>
<svg/onload=alert('XSS')>
<iframe src=javascript:alert('XSS')>
'><script>alert(String.fromCharCode(88,83,83))</script>
"><script>alert(String.fromCharCode(88,83,83))</script>
Résultats :
Payload #42: <script>alert('XSS')</script>
Response Code: 200
Response Size: 2456 bytes
Match: <script>alert('XSS')</script> (reflected)
Exemple 2 : Fuzzing SQL Injection
1. Sélectionner le paramètre ID
2. Add → File Fuzzers → SQL Injection
3. Options :
- Encode: URL encode
- Threads: 5
4. Start Fuzzer
Payloads SQLi utilisés :
' OR '1'='1
' OR '1'='1' --
' OR '1'='1' /*
admin' --
admin' #
' UNION SELECT NULL--
' UNION SELECT NULL,NULL--
1' AND 1=1--
1' AND 1=2--
1' ORDER BY 1--
1' ORDER BY 2--
1' ORDER BY 3--
Résultats :
Payload #15: ' OR '1'='1' --
Response Code: 200
Response Size: 15234 bytes (anomalie: 10x taille normale)
Match: "MySQL syntax error" in response
Exemple 3 : Fuzzing énumération d’ID
1. Requête: GET /user/profile?id=42
2. Sélectionner "42"
3. Add → Numberzz
4. Configuration:
- From: 1
- To: 1000
- Step: 1
5. Start Fuzzer
Analyse des résultats :
ID 1-100 : 200 OK (taille ~2KB)
ID 101 : 403 Forbidden
ID 102-500 : 200 OK (taille ~2KB)
ID 501 : 200 OK (taille ~15KB) ← Anomalie!
ID 502-1000: 200 OK (taille ~2KB)
Conclusion: ID 501 contient plus de données (admin?)
Fuzzing avancé avec payloads personnalisés¶
Créer une liste de payloads :
Fichier custom-sqli.txt :
' OR '1'='1
' OR '1'='1' --
' OR '1'='1' /*
admin' --
admin' #
' UNION SELECT NULL,NULL,NULL--
' AND SLEEP(5)--
'; DROP TABLE users--
' OR 1=1 LIMIT 1--
' OR 'x'='x
Utiliser la liste :
1. Fuzzer → Add → File
2. Sélectionner custom-sqli.txt
3. Start Fuzzer
Fuzzing de multiples paramètres¶
Requête avec plusieurs paramètres :
POST /login.php HTTP/1.1
Host: exemple.com
Content-Type: application/x-www-form-urlencoded
username=admin&password=test123
Fuzzer username ET password simultanément :
-
Sélectionner “admin” → Add → Strings
admin administrator root user test -
Sélectionner “test123” → Add → File
/usr/share/wordlists/rockyou.txt -
Start Fuzzer
Résultats :
Total combinations: 5 usernames × 14,344,392 passwords = 71,721,960 requêtes
Request #42:
username=admin&password=admin123
Response: 302 Redirect to /dashboard
✅ Credentials trouvées: admin:admin123
Fuzzer avec encodage¶
Encodages disponibles : - URL Encoding - Base64 - HTML Entity - Unicode - Hex
Exemple : Bypass WAF avec encodage
1. Payload original: <script>alert('XSS')</script>
2. Add → File Fuzzers → XSS
3. Options → Processors → Add → Encode → URL
4. Options → Processors → Add → Encode → HTML Entity
Résultat:
%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%27%58%53%53%27%29%3C%2F%73%63%72%69%70%74%3E
Analyse des résultats de fuzzing¶
Trier par code de réponse :
Colonne "Code" → Cliquer pour trier
Trier par taille de réponse :
Colonne "Size Resp. Body" → Cliquer pour trier
Identifier les anomalies (tailles différentes)
Rechercher dans les réponses :
Fuzzer → Onglet "Filter"
Response Header: Location
Response Body: error, success, admin, etc.
Exporter les résultats :
Fuzzer → Right click → Export Results
Formats: CSV, HTML, XML
Automatisation et Scripting¶
Scripts ZAP¶
ZAP supporte plusieurs types de scripts pour l’automatisation.
Types de scripts :
| Type | Description | Utilisation |
|---|---|---|
| Stand Alone | Script autonome | Automatisation complète |
| Targeted | Sur une requête spécifique | Tests personnalisés |
| Authentication | Gestion authentification | Login automatique |
| Session Management | Gestion de session | Maintien de session |
| Passive Rules | Scan passif custom | Détection personnalisée |
| Active Rules | Scan actif custom | Attaques personnalisées |
| Proxy | Modification à la volée | Interception automatique |
| HTTP Sender | Avant envoi requête | Ajout headers, etc. |
Langages supportés : - JavaScript (ECMAScript) - Python (Jython) - Groovy - Ruby (JRuby) - Zest (langage graphique)
Scripts Stand Alone¶
Créer un script Stand Alone :
1. Scripts (onglet en bas)
2. Clic droit → New Script
3. Type: Stand Alone
4. Engine: ECMAScript
5. Name: my_custom_script
Exemple 1 : Scanner une liste d’URLs
// Script: bulk_scanner.js
// Type: Stand Alone
// Importer les classes nécessaires
var Thread = Java.type("java.lang.Thread");
var ExtensionActiveScan = Java.type("org.zaproxy.zap.extension.ascan.ExtensionActiveScan");
// Liste des URLs à scanner
var urls = [
"http://exemple1.com",
"http://exemple2.com",
"http://exemple3.com"
];
// Obtenir l'extension de scan actif
var activeScan = control.getExtensionLoader().getExtension(ExtensionActiveScan.class);
// Scanner chaque URL
for (var i = 0; i < urls.length; i++) {
var url = urls[i];
print("Scanning: " + url);
// Accéder à l'URL via le spider d'abord
var extSpider = org.parosproxy.paros.control.Control.getSingleton()
.getExtensionLoader()
.getExtension(org.zaproxy.zap.extension.spider.ExtensionSpider.class);
extSpider.startScan(url, null, 0, null);
// Attendre que le spider se termine
while (extSpider.isScanning()) {
Thread.sleep(1000);
}
print("Spider completed for: " + url);
// Lancer le scan actif
activeScan.startScan(url, null, null, null);
print("Active scan started for: " + url);
}
print("All scans completed!");
Exécuter le script :
Scripts → Clic droit sur le script → Run Script
Exemple 2 : Exporter toutes les alertes
// Script: export_alerts.js
// Type: Stand Alone
var FileWriter = Java.type("java.io.FileWriter");
var SimpleDateFormat = Java.type("java.text.SimpleDateFormat");
var Date = Java.type("java.util.Date");
// Obtenir toutes les alertes
var alerts = org.parosproxy.paros.model.Model.getSingleton()
.getDb().getTableAlert().getAllAlerts();
// Créer le fichier de sortie
var dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
var filename = "/tmp/zap_alerts_" + dateFormat.format(new Date()) + ".csv";
var writer = new FileWriter(filename);
// En-tête CSV
writer.write("Alert,Risk,Confidence,URL,Parameter,Evidence\n");
// Écrire chaque alerte
for (var i = 0; i < alerts.size(); i++) {
var alert = alerts.get(i);
var line =
"\"" + alert.getAlert() + "\"," +
"\"" + alert.getRisk() + "\"," +
"\"" + alert.getConfidence() + "\"," +
"\"" + alert.getUri() + "\"," +
"\"" + alert.getParam() + "\"," +
"\"" + alert.getEvidence() + "\"\n";
writer.write(line);
}
writer.close();
print("Alerts exported to: " + filename);
Scripts Targeted¶
Scripts exécutés sur une requête sélectionnée.
Créer un script Targeted :
// Script: encode_param.js
// Type: Targeted
function invokeWith(msg) {
// Obtenir le corps de la requête
var body = msg.getRequestBody().toString();
// Encoder le paramètre en base64
var Base64 = Java.type("java.util.Base64");
var encoded = Base64.getEncoder().encodeToString(body.getBytes());
print("Original: " + body);
print("Encoded: " + encoded);
// Modifier la requête
msg.getRequestBody().setBody(encoded);
// Renvoyer la requête modifiée
org.parosproxy.paros.network.HttpSender
.sendAndReceive(msg, msg.getRequestHeader().isSecure());
// Afficher la réponse
print("Response Code: " + msg.getResponseHeader().getStatusCode());
print("Response Body: " + msg.getResponseBody().toString());
}
Utiliser le script :
1. Sélectionner une requête dans History
2. Clic droit → Invoke with script → encode_param.js
Scripts Authentication¶
Automatise le processus de connexion.
Exemple : Script de login personnalisé
// Script: custom_auth.js
// Type: Authentication
function authenticate(helper, paramsValues, credentials) {
var HttpRequestHeader = Java.type("org.parosproxy.paros.network.HttpRequestHeader");
var HttpMessage = Java.type("org.parosproxy.paros.network.HttpMessage");
var URI = Java.type("org.apache.commons.httpclient.URI");
// URL de login
var loginUrl = "http://exemple.com/login.php";
// Créer la requête de login
var requestUri = new URI(loginUrl, false);
var requestMethod = HttpRequestHeader.POST;
// Corps de la requête
var username = credentials.getParam("username");
var password = credentials.getParam("password");
var postData = "username=" + username + "&password=" + password;
// Construire la requête
var msg = helper.prepareMessage();
msg.getRequestHeader().setMethod(requestMethod);
msg.getRequestHeader().setURI(requestUri);
msg.setRequestBody(postData);
msg.getRequestHeader().setContentLength(msg.getRequestBody().length());
// Envoyer la requête
helper.sendAndReceive(msg);
// Vérifier le succès (présence de "dashboard" dans la réponse)
var responseBody = msg.getResponseBody().toString();
if (responseBody.indexOf("dashboard") !== -1) {
return msg;
}
return null;
}
function getRequiredParamsNames() {
return ["username", "password"];
}
function getOptionalParamsNames() {
return [];
}
function getCredentialsParamsNames() {
return ["username", "password"];
}
Scripts Passive Rules¶
Détection personnalisée de vulnérabilités sans scan actif.
Exemple : Détecter des secrets dans les réponses
// Script: detect_secrets.js
// Type: Passive Rules
var extensionAlert = control.getExtensionLoader()
.getExtension(org.zaproxy.zap.extension.alert.ExtensionAlert.class);
function scan(ps, msg, src) {
var body = msg.getResponseBody().toString();
var url = msg.getRequestHeader().getURI().toString();
// Patterns de secrets
var patterns = [
{
name: "AWS Access Key",
regex: /AKIA[0-9A-Z]{16}/g,
risk: 3 // High
},
{
name: "Private Key",
regex: /-----BEGIN (RSA |DSA |EC )?PRIVATE KEY-----/g,
risk: 3
},
{
name: "API Key",
regex: /api[_-]?key["\s:=]+[a-zA-Z0-9]{32,}/gi,
risk: 2 // Medium
},
{
name: "Password in Code",
regex: /password["\s:=]+["'][^"']{8,}["']/gi,
risk: 2
}
];
// Chercher chaque pattern
patterns.forEach(function(pattern) {
var matches = body.match(pattern.regex);
if (matches) {
matches.forEach(function(match) {
// Créer une alerte
var alertRisk = pattern.risk;
var alertConfidence = 2; // Medium
var alertTitle = pattern.name + " Detected";
var alertDesc = "A " + pattern.name + " was found in the response.";
var alertSolution = "Remove sensitive information from responses.";
var alertReference = "https://owasp.org/www-project-top-ten/";
ps.raiseAlert(
alertRisk,
alertConfidence,
alertTitle,
alertDesc,
url,
"",
"",
match,
alertSolution,
"",
0, // CWE ID
0, // WASC ID
msg
);
});
}
});
}
Scripts Active Rules¶
Tests personnalisés avec payloads malveillants.
Exemple : Test SSTI (Server-Side Template Injection)
// Script: ssti_scanner.js
// Type: Active Rules
function scan(as, msg, param, value) {
// Payloads SSTI
var payloads = [
"{{7*7}}",
"${7*7}",
"<%= 7*7 %>",
"${{7*7}}",
"#{7*7}",
"*{7*7}"
];
var expectedResult = "49";
payloads.forEach(function(payload) {
// Créer une nouvelle requête avec le payload
var testMsg = msg.cloneRequest();
as.setParam(testMsg, param, payload);
// Envoyer la requête
as.sendAndReceive(testMsg, false, false);
// Analyser la réponse
var response = testMsg.getResponseBody().toString();
if (response.indexOf(expectedResult) !== -1) {
// Vulnérabilité détectée!
as.raiseAlert(
3, // High risk
3, // High confidence
"Server-Side Template Injection",
"SSTI vulnerability detected. The application evaluates template expressions.",
testMsg.getRequestHeader().getURI().toString(),
param,
payload,
"Response contains: " + expectedResult,
"Use a safe template engine and escape user input.",
"Payload: " + payload + "\nExpected: " + expectedResult,
0, // CWE-94
0, // WASC
testMsg
);
return; // Stop after first detection
}
});
}
API ZAP pour l’automatisation¶
ZAP expose une API REST complète.
Activer l’API :
Tools → Options → API
- Enable API: checked
- API Key: (générer une clé ou laisser vide pour mode insecure)
- Addresses permitted to use the API: localhost
Exemples d’utilisation de l’API :
1. Accéder au spider via API
# Lancer le spider
curl "http://localhost:8080/JSON/spider/action/scan/?url=http://exemple.com&apikey=YOUR_API_KEY"
# Vérifier le statut
curl "http://localhost:8080/JSON/spider/view/status/?apikey=YOUR_API_KEY"
# Résultats
{"status":"100"} # 100% = terminé
2. Lancer un scan actif
# Lancer le scan
curl "http://localhost:8080/JSON/ascan/action/scan/?url=http://exemple.com&apikey=YOUR_API_KEY"
# Récupérer le scan ID
# {"scan":"0"}
# Vérifier le statut
curl "http://localhost:8080/JSON/ascan/view/status/?scanId=0&apikey=YOUR_API_KEY"
# Résultats
{"status":"45"} # 45% complété
3. Récupérer les alertes
# Toutes les alertes
curl "http://localhost:8080/JSON/alert/view/alerts/?apikey=YOUR_API_KEY"
# Alertes pour une URL spécifique
curl "http://localhost:8080/JSON/alert/view/alerts/?url=http://exemple.com&apikey=YOUR_API_KEY"
# Alertes high risk uniquement
curl "http://localhost:8080/JSON/alert/view/alertsByRisk/?url=http://exemple.com&risk=High&apikey=YOUR_API_KEY"
4. Script Python avec l’API
#!/usr/bin/env python3
import requests
import time
import json
ZAP_URL = "http://localhost:8080"
API_KEY = "your-api-key-here"
TARGET_URL = "http://exemple.com"
def zap_spider(url):
"""Lance le spider sur une URL"""
endpoint = f"{ZAP_URL}/JSON/spider/action/scan/"
params = {"url": url, "apikey": API_KEY}
response = requests.get(endpoint, params=params)
return response.json()
def zap_spider_status():
"""Vérifie le statut du spider"""
endpoint = f"{ZAP_URL}/JSON/spider/view/status/"
params = {"apikey": API_KEY}
response = requests.get(endpoint, params=params)
return int(response.json()["status"])
def zap_active_scan(url):
"""Lance un scan actif"""
endpoint = f"{ZAP_URL}/JSON/ascan/action/scan/"
params = {"url": url, "apikey": API_KEY}
response = requests.get(endpoint, params=params)
return response.json()["scan"]
def zap_scan_status(scan_id):
"""Vérifie le statut du scan actif"""
endpoint = f"{ZAP_URL}/JSON/ascan/view/status/"
params = {"scanId": scan_id, "apikey": API_KEY}
response = requests.get(endpoint, params=params)
return int(response.json()["status"])
def zap_get_alerts():
"""Récupère toutes les alertes"""
endpoint = f"{ZAP_URL}/JSON/alert/view/alerts/"
params = {"apikey": API_KEY}
response = requests.get(endpoint, params=params)
return response.json()["alerts"]
def main():
print(f"[*] Starting scan of {TARGET_URL}")
# 1. Spider
print("[*] Starting spider...")
zap_spider(TARGET_URL)
while zap_spider_status() < 100:
print(f"[*] Spider progress: {zap_spider_status()}%")
time.sleep(2)
print("[+] Spider completed")
# 2. Active Scan
print("[*] Starting active scan...")
scan_id = zap_active_scan(TARGET_URL)
while zap_scan_status(scan_id) < 100:
print(f"[*] Scan progress: {zap_scan_status(scan_id)}%")
time.sleep(5)
print("[+] Active scan completed")
# 3. Récupérer les alertes
print("[*] Retrieving alerts...")
alerts = zap_get_alerts()
# Compter par sévérité
high = sum(1 for a in alerts if a["risk"] == "High")
medium = sum(1 for a in alerts if a["risk"] == "Medium")
low = sum(1 for a in alerts if a["risk"] == "Low")
info = sum(1 for a in alerts if a["risk"] == "Informational")
print(f"\n[+] Results:")
print(f" High: {high}")
print(f" Medium: {medium}")
print(f" Low: {low}")
print(f" Informational: {info}")
# Sauvegarder dans un fichier
with open("zap_alerts.json", "w") as f:
json.dump(alerts, f, indent=2)
print(f"\n[+] Full report saved to zap_alerts.json")
if __name__ == "__main__":
main()
Exécuter le script :
chmod +x zap_automation.py
./zap_automation.py
API Testing¶
Configuration pour tester des APIs¶
ZAP est excellent pour tester les APIs REST, SOAP, et GraphQL.
API REST¶
Méthode 1 : Import OpenAPI/Swagger
1. Import → Import an OpenAPI definition
2. Choisir le fichier (swagger.json, openapi.yaml)
3. Ou entrer l'URL (http://api.exemple.com/swagger.json)
4. Cliquer "Import"
Les endpoints sont automatiquement ajoutés au Sites Tree.
Méthode 2 : Utilisation manuelle
Tools → Manual Request Editor
Exemple de requête API :
POST /api/v1/users HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
{
"username": "john",
"email": "john@exemple.com",
"role": "user"
}
Tester différents verbes HTTP :
# GET - Récupérer des données
GET /api/v1/users/42 HTTP/1.1
Host: api.exemple.com
Authorization: Bearer token123
# POST - Créer une ressource
POST /api/v1/users HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
Authorization: Bearer token123
{"username": "alice", "email": "alice@test.com"}
# PUT - Mettre à jour complètement
PUT /api/v1/users/42 HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
Authorization: Bearer token123
{"username": "alice_updated", "email": "alice@updated.com"}
# PATCH - Mettre à jour partiellement
PATCH /api/v1/users/42 HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
Authorization: Bearer token123
{"email": "newemail@test.com"}
# DELETE - Supprimer une ressource
DELETE /api/v1/users/42 HTTP/1.1
Host: api.exemple.com
Authorization: Bearer token123
Fuzzing d’API REST :
Test 1 : Énumération d’IDs
1. Requête: GET /api/v1/users/1
2. Clic droit → Attack → Fuzz
3. Sélectionner "1"
4. Add → Numberzz (1 to 1000)
5. Start Fuzzer
Résultats attendus :
ID 1-50: 200 OK (utilisateurs existants)
ID 51-99: 404 Not Found
ID 100: 200 OK (admin? taille différente)
ID 101+: 404 Not Found
Test 2 : Manipulation de rôles
POST /api/v1/users HTTP/1.1
Content-Type: application/json
{"username": "test", "email": "test@test.com", "role": "admin"}
Fuzzer le champ “role” :
Payloads:
- user
- admin
- superadmin
- root
- moderator
- guest
Test 3 : Injection dans JSON
1. Requête avec JSON body
2. Fuzzer un champ
3. Payloads: File Fuzzers → SQL Injection
Exemple :
{
"username": "' OR '1'='1",
"email": "test@test.com"
}
API GraphQL¶
Installer l’add-on GraphQL :
1. Manage Add-ons → Marketplace
2. Rechercher "GraphQL"
3. Installer
Importer un schéma GraphQL :
1. Import → Import a GraphQL Schema
2. URL endpoint: http://api.exemple.com/graphql
3. Ou upload schema.graphql
4. Cliquer "Import"
Exemple de requête GraphQL :
POST /graphql HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
{
"query": "{ users { id username email } }"
}
Tester les mutations :
POST /graphql HTTP/1.1
Host: api.exemple.com
Content-Type: application/json
{
"query": "mutation { createUser(username: \"test\", email: \"test@test.com\", role: \"admin\") { id username role } }"
}
Fuzzing GraphQL :
1. Sélectionner la valeur "test" dans username
2. Fuzz avec payloads XSS/SQLi
3. Observer les réponses
Test d’introspection GraphQL :
POST /graphql HTTP/1.1
Content-Type: application/json
{
"query": "{ __schema { types { name fields { name } } } }"
}
Si l’introspection est activée, vous obtenez tout le schéma de l’API.
API SOAP¶
Importer un WSDL :
1. Import → Import a WSDL file
2. URL: http://exemple.com/service?wsdl
3. Cliquer "Import"
Exemple de requête SOAP :
POST /service HTTP/1.1
Host: exemple.com
Content-Type: text/xml; charset=utf-8
SOAPAction: "http://exemple.com/GetUser"
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<GetUser xmlns="http://exemple.com/">
<UserId>42</UserId>
</GetUser>
</soap:Body>
</soap:Envelope>
Fuzzing SOAP :
1. Sélectionner <UserId>42</UserId>
2. Fuzzer la valeur "42"
3. Tester avec:
- Nombres: 1-1000
- Strings: admin, root, etc.
- Injections: SQLi, XPath, XXE
Test XXE (XML External Entity) :
<?xml version="1.0"?>
<!DOCTYPE foo [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<GetUser xmlns="http://exemple.com/">
<UserId>&xxe;</UserId>
</GetUser>
</soap:Body>
</soap:Envelope>
Authentication et Session Management¶
Configurer l’authentification¶
ZAP supporte plusieurs méthodes d’authentification.
Types d’authentification supportés : - Form-based (formulaire HTML) - HTTP/NTLM Authentication - Script-based (personnalisé) - JSON-based (API) - Manual (authentification manuelle)
Form-Based Authentication¶
Scénario : Site avec login classique
Étape 1 : Créer un contexte
1. Clic droit sur site → Include in Context → New Context
2. Name: "MyWebApp"
3. Include in Context: http://exemple.com/.*
4. Exclude from Context: http://exemple.com/logout
Étape 2 : Configurer l’authentification
1. Clic droit sur contexte → Flag as Context → Authentication
2. Method: Form-Based Authentication
3. Login URL: http://exemple.com/login.php
4. Login Request:
Capturer la requête de login :
1. Se connecter manuellement via le proxy ZAP
2. Trouver la requête POST dans History
3. Clic droit → Flag as Context → Authentication Login Request
Exemple de requête de login :
POST /login.php HTTP/1.1
Host: exemple.com
Content-Type: application/x-www-form-urlencoded
username={%username%}&password={%password%}&submit=Login
Les paramètres {%username%} et {%password%} seront remplacés automatiquement.
Étape 3 : Définir l’indicateur de session
ZAP doit savoir si vous êtes connecté ou non.
Authentication → Logged In Indicator (regex):
<a href="/logout">Logout</a>
Ou Logged Out Indicator (regex):
<a href="/login">Login</a>
Étape 4 : Ajouter des utilisateurs
1. Users (dans le Context) → Add
2. Username: admin
3. Password: admin123
4. Enabled: checked
Étape 5 : Tester l’authentification
1. Clic droit sur le user → Test Authentication
2. Vérifier dans la sortie:
- Login request sent
- Logged in indicator found: TRUE
Exemple de sortie :
[INFO] Authentication Test Started
[INFO] Sending login request to http://exemple.com/login.php
[INFO] Login request completed (HTTP 302)
[INFO] Following redirect to /dashboard
[INFO] Checking logged in indicator: <a href="/logout">Logout</a>
[INFO] Logged in indicator FOUND
[SUCCESS] Authentication successful for user: admin
Script-Based Authentication¶
Pour les authentifications complexes (OAuth, JWT, 2FA, etc.)
Exemple : Authentification JWT
// Script: jwt_auth.js
// Type: Authentication
function authenticate(helper, paramsValues, credentials) {
var HttpRequestHeader = Java.type("org.parosproxy.paros.network.HttpRequestHeader");
var HttpMessage = Java.type("org.parosproxy.paros.network.HttpMessage");
var URI = Java.type("org.apache.commons.httpclient.URI");
// Endpoint de login
var loginUrl = "http://api.exemple.com/auth/login";
// Construire la requête JSON
var username = credentials.getParam("username");
var password = credentials.getParam("password");
var jsonBody = JSON.stringify({
"username": username,
"password": password
});
// Créer la requête
var msg = helper.prepareMessage();
var requestUri = new URI(loginUrl, false);
msg.getRequestHeader().setMethod(HttpRequestHeader.POST);
msg.getRequestHeader().setURI(requestUri);
msg.getRequestHeader().setHeader("Content-Type", "application/json");
msg.setRequestBody(jsonBody);
msg.getRequestHeader().setContentLength(msg.getRequestBody().length());
// Envoyer la requête
helper.sendAndReceive(msg);
// Extraire le token JWT de la réponse
var responseBody = msg.getResponseBody().toString();
var response = JSON.parse(responseBody);
if (response.token) {
// Stocker le token pour les requêtes suivantes
var token = response.token;
msg.getRequestHeader().setHeader("Authorization", "Bearer " + token);
return msg;
}
return null;
}
function getRequiredParamsNames() {
return ["username", "password"];
}
function getOptionalParamsNames() {
return [];
}
function getCredentialsParamsNames() {
return ["username", "password"];
}
Configurer :
1. Context → Authentication
2. Method: Script-Based Authentication
3. Load Script: jwt_auth.js
4. Logged In Indicator: "token": "(present dans la réponse)
Session Management¶
Types de session management : - Cookie-Based (défaut) - HTTP Authentication - Script-Based
Cookie-Based Session (défaut) :
Context → Session Management
Method: Cookie-Based Session Management
ZAP gère automatiquement les cookies (PHPSESSID, JSESSIONID, etc.)
Script-Based Session Management :
Pour ajouter automatiquement des headers à chaque requête.
// Script: add_jwt_header.js
// Type: HTTP Sender
function sendingRequest(msg, initiator, helper) {
// Récupérer le token JWT (stocké globalement ou via script d'auth)
var token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
// Ajouter le header Authorization
msg.getRequestHeader().setHeader("Authorization", "Bearer " + token);
}
function responseReceived(msg, initiator, helper) {
// Optionnel: Rafraîchir le token si expiré
var responseBody = msg.getResponseBody().toString();
if (responseBody.indexOf("token_expired") !== -1) {
// Ré-authentifier et obtenir un nouveau token
// (appeler le script d'auth)
}
}
Activer le script :
Scripts → HTTP Sender → Enable add_jwt_header.js
Forced User Mode¶
Force ZAP à toujours utiliser un utilisateur spécifique.
Activer :
1. Context → Users
2. Sélectionner un user
3. Cliquer "Set as Forced User"
4. Toolbar → Force User Mode ON (icône utilisateur)
Utilisation : - Tous les scans utiliseront cet utilisateur - Utile pour tester les fonctionnalités authentifiées - Permet de tester différents niveaux de privilèges
Exemple de test avec 2 utilisateurs :
User 1: admin / admin123 (role: admin)
User 2: john / john123 (role: user)
1. Set "john" as Forced User
2. Active Scan sur /admin/
3. Observer les résultats (403 Forbidden?)
4. Set "admin" as Forced User
5. Active Scan sur /admin/
6. Observer les résultats (200 OK, vulnérabilités détectées)
Anti-CSRF Token Handling¶
ZAP gère automatiquement les tokens CSRF.
Configuration :
Tools → Options → Anti CSRF Tokens
Add token name: csrf_token, _csrf, authenticity_token
ZAP extraira automatiquement ces tokens et les réutilisera.
Exemple :
Requête 1 : Obtenir le formulaire
GET /transfer HTTP/1.1
Réponse :
<form action="/transfer" method="POST">
<input type="hidden" name="csrf_token" value="abc123xyz789">
<input type="text" name="amount">
<input type="submit" value="Transfer">
</form>
Requête 2 : Soumettre le formulaire
POST /transfer HTTP/1.1
Content-Type: application/x-www-form-urlencoded
csrf_token=abc123xyz789&amount=1000
ZAP extraira automatiquement csrf_token=abc123xyz789 et le réutilisera.
Reporting et Documentation¶
Générer un rapport¶
ZAP offre plusieurs formats de rapports.
Générer un rapport HTML :
Report → Generate HTML Report
1. Title: "Security Assessment - MyApp"
2. Template: Traditional HTML
3. Report file name: zap_report.html
4. Include: All Alerts
5. Generate Report
Générer un rapport XML :
Report → Generate XML Report
Formats disponibles : - HTML : Rapport détaillé avec styling - XML : Format structuré pour parsing - JSON : Pour intégration avec d’autres outils - Markdown : Pour documentation - PDF : Nécessite un add-on
Structure d’un rapport HTML¶
1. Summary
- Total URLs analyzed
- Alerts by risk level
- Alerts by confidence
2. Alerts
- High Risk
- [Alert Name]
- Description
- URL(s)
- Parameter
- Attack
- Evidence
- Solution
- Reference
- CWE ID
- WASC ID
- Medium Risk
- Low Risk
- Informational
3. Appendix
- Alert counts by type
- Alert counts by site
Personnaliser les rapports¶
Installer le Report Generation add-on :
Manage Add-ons → Marketplace → "Report Generation"
Templates disponibles : - Traditional HTML - Modern HTML (avec graphiques) - Traditional HTML Plus - Risk and Confidence HTML - Traditional XML - Traditional MD (Markdown)
Créer un template personnalisé :
1. Aller dans ~/.ZAP/reports/
2. Copier un template existant
3. Modifier le template (Thymeleaf syntax)
4. Utiliser dans Report → Generate Report
Exporter les alertes en CSV¶
# Via API
curl "http://localhost:8080/OTHER/core/other/csvreport/?apikey=YOUR_KEY" -o report.csv
# Via script Python
import requests
import csv
ZAP_URL = "http://localhost:8080"
API_KEY = "your-api-key"
# Récupérer les alertes
alerts = requests.get(
f"{ZAP_URL}/JSON/alert/view/alerts/",
params={"apikey": API_KEY}
).json()["alerts"]
# Écrire en CSV
with open("zap_alerts.csv", "w", newline="") as csvfile:
fieldnames = ["alert", "risk", "confidence", "url", "param", "evidence", "solution"]
writer = csv.DictWriter(csvfile, fieldnames=fieldnames)
writer.writeheader()
for alert in alerts:
writer.writerow({
"alert": alert["alert"],
"risk": alert["risk"],
"confidence": alert["confidence"],
"url": alert["url"],
"param": alert["param"],
"evidence": alert["evidence"],
"solution": alert["solution"]
})
print("Report saved to zap_alerts.csv")
Comparer des scans¶
Installer l’add-on “Diff” :
Manage Add-ons → Marketplace → "Diff"
Comparer deux sessions :
1. Charger la première session (scan baseline)
2. Tools → Compare with another session
3. Sélectionner la deuxième session (nouveau scan)
4. Le rapport montre :
- Nouvelles alertes
- Alertes résolues
- Alertes inchangées
Exemple de rapport de comparaison :
Comparison Report: Baseline vs New Scan
Summary:
- Total alerts (baseline): 45
- Total alerts (new): 38
- New alerts: 5
- Resolved alerts: 12
- Unchanged alerts: 33
New Alerts (5):
1. [High] SQL Injection in /api/products?id=
2. [Medium] XSS in /search?q=
3. [Low] Cookie without SameSite
4. [Info] Deprecated TLS version
5. [Info] Missing X-Frame-Options
Resolved Alerts (12):
1. [High] Path Traversal in /download (FIXED)
2. [Medium] CSRF in /transfer (FIXED)
...
ZAP en Mode Headless/CLI¶
Lancement en mode daemon¶
ZAP peut fonctionner sans interface graphique.
# Lancer ZAP en mode daemon
zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.disablekey=true
# Avec API key
zap.sh -daemon -host 0.0.0.0 -port 8080 -config api.key=your-secret-key
# Écouter uniquement sur localhost
zap.sh -daemon -port 8080
Vérifier que ZAP fonctionne :
curl http://localhost:8080/JSON/core/view/version/
# {"version":"2.14.0"}
Automation Framework¶
ZAP 2.12+ introduit l’Automation Framework (meilleure méthode pour CI/CD).
Créer un plan d’automatisation (YAML) :
Fichier zap-automation.yaml :
---
env:
contexts:
- name: "MyApp"
urls:
- "http://exemple.com"
includePaths:
- "http://exemple.com/.*"
excludePaths:
- "http://exemple.com/logout.*"
parameters:
failOnError: true
failOnWarning: false
progressToStdout: true
jobs:
- type: spider
parameters:
maxDuration: 5
maxDepth: 10
numberOfThreads: 5
- type: spiderAjax
parameters:
maxDuration: 5
maxCrawlDepth: 10
numberOfBrowsers: 2
- type: passiveScan-wait
parameters:
maxDuration: 10
- type: activeScan
parameters:
policy: "Default Policy"
maxRuleDurationInMins: 1
maxScanDurationInMins: 10
- type: report
parameters:
template: "traditional-html"
reportDir: "/tmp/zap-reports"
reportFile: "zap-report"
reportTitle: "Security Assessment Report"
reportDescription: "Automated security scan"
Exécuter le plan :
# Avec ZAP installé
zap.sh -cmd -autorun /path/to/zap-automation.yaml
# Avec Docker
docker run --rm -v $(pwd):/zap/wrk:rw zaproxy/zap-stable zap.sh \
-cmd -autorun /zap/wrk/zap-automation.yaml
Plan d’automatisation avec authentification :
---
env:
contexts:
- name: "AuthApp"
urls:
- "http://exemple.com"
authentication:
method: "form"
parameters:
loginPageUrl: "http://exemple.com/login"
loginRequestUrl: "http://exemple.com/auth"
loginRequestBody: "username={%username%}&password={%password%}"
verification:
method: "response"
loggedInRegex: "\\QLogout\\E"
loggedOutRegex: "\\QLogin\\E"
users:
- name: "testuser"
credentials:
username: "admin"
password: "admin123"
sessionManagement:
method: "cookie"
jobs:
- type: spider
parameters:
user: "testuser"
maxDuration: 5
- type: activeScan
parameters:
user: "testuser"
policy: "Default Policy"
- type: report
parameters:
template: "traditional-html"
reportFile: "authenticated-scan-report"
Baseline Scan (scan rapide)¶
Scan passif uniquement, idéal pour CI/CD.
# Baseline scan
zap-baseline.py -t http://exemple.com
# Avec rapport
zap-baseline.py -t http://exemple.com -r baseline-report.html
# Ignorer certains types d'alertes
zap-baseline.py -t http://exemple.com -c baseline-config.conf
Fichier de configuration baseline-config.conf :
# Ignorer les alertes de faible priorité
10015 IGNORE (Cookie Without Secure Flag)
10054 IGNORE (Cookie Without SameSite Attribute)
# Ignorer pour des URLs spécifiques
10021 IGNORE (X-Content-Type-Options) http://exemple.com/static/.*
# Fail sur High risk uniquement
FAIL-HIGH
Sortie :
PASS: Cookie No HttpOnly Flag [10010]
PASS: Cross-Domain Misconfiguration [10098]
WARN-NEW: Cookie Without Secure Flag [10011] x 5
http://exemple.com/ (200 OK)
http://exemple.com/login (200 OK)
FAIL-NEW: SQL Injection [40018] x 3
http://exemple.com/product?id=1 (200 OK)
FAIL-NEW: 1 FAIL-INPROG: 0 WARN-NEW: 1 WARN-INPROG: 0 INFO: 0 IGNORE: 2 PASS: 45
Full Scan (scan complet)¶
Spider + Active Scan automatique.
# Full scan
zap-full-scan.py -t http://exemple.com
# Avec rapport et configuration
zap-full-scan.py -t http://exemple.com \
-r full-scan-report.html \
-c full-scan-config.conf \
-m 10 # Maximum 10 minutes
API Scan¶
Scan spécialisé pour les APIs.
# API scan avec OpenAPI/Swagger
zap-api-scan.py -t http://api.exemple.com/openapi.json \
-f openapi \
-r api-scan-report.html
# API scan avec GraphQL
zap-api-scan.py -t http://api.exemple.com/graphql \
-f graphql \
-r graphql-scan-report.html
Intégration CI/CD¶
Intégration avec Jenkins¶
Installer le plugin ZAP :
Jenkins → Manage Plugins → Available → "OWASP ZAP"
Jenkinsfile exemple :
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Deploy to Test') {
steps {
sh './deploy-test.sh'
}
}
stage('ZAP Security Scan') {
steps {
script {
// Démarrer ZAP en daemon
sh '''
docker run -d --name zap \
-p 8080:8080 \
-v $(pwd)/zap-reports:/zap/wrk:rw \
zaproxy/zap-stable \
zap.sh -daemon -host 0.0.0.0 -port 8080 \
-config api.disablekey=true
'''
// Attendre que ZAP démarre
sh 'sleep 30'
// Exécuter le scan
sh '''
docker exec zap zap-cli quick-scan \
--self-contained \
--start-options '-config api.disablekey=true' \
http://test.exemple.com
'''
// Générer le rapport
sh '''
docker exec zap zap-cli report \
-o /zap/wrk/zap-report.html \
-f html
'''
// Arrêter ZAP
sh 'docker stop zap && docker rm zap'
}
}
}
stage('Publish Report') {
steps {
publishHTML([
reportDir: 'zap-reports',
reportFiles: 'zap-report.html',
reportName: 'ZAP Security Report'
])
}
}
}
post {
failure {
emailext (
subject: "ZAP Security Scan Failed: ${env.JOB_NAME}",
body: "Check console output at ${env.BUILD_URL}",
to: "security@exemple.com"
)
}
}
}
Intégration avec GitLab CI¶
.gitlab-ci.yml :
stages:
- build
- test
- security
- deploy
build:
stage: build
script:
- npm install
- npm run build
artifacts:
paths:
- dist/
deploy_test:
stage: test
script:
- ./deploy-to-test.sh
environment:
name: test
url: http://test.exemple.com
zap_scan:
stage: security
image: zaproxy/zap-stable
script:
- mkdir -p /zap/wrk/reports
- zap-baseline.py -t http://test.exemple.com -r /zap/wrk/reports/baseline.html -c baseline.conf || true
- zap-full-scan.py -t http://test.exemple.com -r /zap/wrk/reports/full.html -m 10 || true
artifacts:
when: always
paths:
- /zap/wrk/reports/
reports:
junit: /zap/wrk/reports/*.xml
allow_failure: true
deploy_prod:
stage: deploy
script:
- ./deploy-to-prod.sh
when: manual
only:
- main
Intégration avec GitHub Actions¶
.github/workflows/zap-scan.yml :
name: ZAP Security Scan
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
schedule:
- cron: '0 2 * * 1' # Every Monday at 2am
jobs:
zap_scan:
runs-on: ubuntu-latest
name: ZAP Baseline Scan
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: ZAP Baseline Scan
uses: zaproxy/action-baseline@v0.7.0
with:
target: 'https://test.exemple.com'
rules_file_name: '.zap/rules.tsv'
cmd_options: '-a'
- name: Upload ZAP Report
uses: actions/upload-artifact@v3
if: always()
with:
name: zap-report
path: report_html.html
- name: Create Issue on Failure
if: failure()
uses: actions/github-script@v6
with:
script: |
github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'ZAP Security Scan Failed',
body: 'ZAP scan detected security issues. Check the workflow run for details.',
labels: ['security', 'zap']
})
Fichier de règles .zap/rules.tsv :
10015 IGNORE (Cookie Without Secure Flag - Dev environment)
10054 IGNORE (Cookie Without SameSite - Dev environment)
10011 WARN (Cookie No HttpOnly Flag)
10098 FAIL (Cross-Domain Misconfiguration)
40018 FAIL (SQL Injection)
40012 FAIL (Cross Site Scripting)
Intégration avec Azure DevOps¶
azure-pipelines.yml :
trigger:
- main
- develop
pool:
vmImage: 'ubuntu-latest'
steps:
- task: Docker@2
displayName: 'Start ZAP Container'
inputs:
command: 'run'
arguments: >
-d --name zap
-p 8080:8080
-v $(Build.ArtifactStagingDirectory):/zap/wrk:rw
zaproxy/zap-stable
zap.sh -daemon -host 0.0.0.0 -port 8080
-config api.disablekey=true
- bash: |
sleep 30
docker exec zap zap-baseline.py -t http://test.exemple.com -r /zap/wrk/baseline.html
displayName: 'Run ZAP Baseline Scan'
continueOnError: true
- task: PublishBuildArtifacts@1
displayName: 'Publish ZAP Report'
inputs:
PathtoPublish: '$(Build.ArtifactStagingDirectory)'
ArtifactName: 'zap-reports'
- bash: |
docker stop zap && docker rm zap
displayName: 'Stop ZAP Container'
condition: always()
Extensions et Add-ons¶
Marketplace ZAP¶
Toolbar → Manage Add-ons (icône puzzle)
Onglets : - Installed : Extensions installées - Marketplace : Extensions officielles - Uninstalled : Extensions disponibles mais pas installées
Add-ons essentiels¶
1. AJAX Spider
Marketplace → AJAX Spider → Install
Pour les applications JavaScript/SPA.
2. GraphQL Support
Marketplace → GraphQL Support → Install
Import et test de schémas GraphQL.
3. Advanced SQLInjection Scanner
Marketplace → Advanced SQLInjection Scanner → Install
Tests d’injection SQL plus approfondis.
4. DOM XSS Scanner
Marketplace → DOM XSS → Install
Détection de XSS basées sur le DOM.
5. Wappalyzer - Technology Detection
Marketplace → Wappalyzer → Install
Identifie les technologies utilisées (frameworks, CMS, serveurs).
6. Retire.js
Marketplace → Retire.js → Install
Détecte les bibliothèques JavaScript vulnérables.
7. JWT Support
Marketplace → JWT Support → Install
Décode et manipule les JSON Web Tokens.
8. Directory List v2.3
Marketplace → Directory List → Install
Listes de répertoires pour forced browsing.
9. FuzzDB Files
Marketplace → FuzzDB Files → Install
Payloads de fuzzing additionnels.
10. Report Generation
Marketplace → Report Generation → Install
Templates de rapports supplémentaires.
Utilisation de l’add-on JWT Support¶
Exemple :
-
Intercepter une requête avec JWT :
http GET /api/users HTTP/1.1 Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c -
Clic droit → Show JWT
-
Le JWT est décodé : ```json Header: { “alg”: “HS256”, “typ”: “JWT” }
Payload: { “sub”: “1234567890”, “name”: “John Doe”, “iat”: 1516239022 } ```
-
Modifier le payload :
json { "sub": "1234567890", "name": "Admin", "role": "admin", "iat": 1516239022 } -
Fuzzer l’algorithme (attaque None) :
json Header: { "alg": "none", "typ": "JWT" } -
Tester la signature : - Bruteforce de la clé secrète - Test de clés faibles (secret, password, 123456)
Utilisation de Wappalyzer¶
Après spider ou navigation :
1. Clic droit sur un site
2. Wappalyzer → Detect Technologies
Résultats :
- Web Server: Apache 2.4.41
- Programming Language: PHP 7.4.3
- Framework: Laravel 8.x
- JavaScript Library: jQuery 3.5.1
- CMS: WordPress 5.9
- Database: MySQL
- CDN: Cloudflare
Utilité : - Adapter les tests aux technologies détectées - Identifier les versions vulnérables - Optimiser la politique de scan
Créer son propre add-on¶
ZAP permet de créer des add-ons personnalisés en Java.
Structure d’un add-on :
my-addon/
├── src/
│ └── org/zaproxy/zap/extension/myaddon/
│ ├── ExtensionMyAddon.java
│ ├── MyAddonPanel.java
│ └── resources/
│ └── Messages.properties
├── build.gradle
└── ZapAddOn.xml
Exemple simple : ExtensionMyAddon.java
package org.zaproxy.zap.extension.myaddon;
import org.parosproxy.paros.extension.ExtensionAdaptor;
import org.parosproxy.paros.extension.ExtensionHook;
public class ExtensionMyAddon extends ExtensionAdaptor {
public ExtensionMyAddon() {
super();
setName("MyCustomAddon");
}
@Override
public void hook(ExtensionHook extensionHook) {
super.hook(extensionHook);
// Ajouter un panel personnalisé
if (getView() != null) {
extensionHook.getHookView().addStatusPanel(new MyAddonPanel());
}
}
@Override
public String getAuthor() {
return "Your Name";
}
@Override
public String getDescription() {
return "My custom ZAP addon";
}
}
Cas Pratiques et Scénarios Réels¶
Scénario 1 : Test d’une application e-commerce¶
Objectif : Tester une boutique en ligne de bout en bout.
Étapes :
- Configuration initiale ```
- Lancer ZAP
- Créer un nouveau contexte “EcommerceApp”
- Include: https://shop.exemple.com/.*
-
Exclude: https://shop.exemple.com/logout ```
-
Exploration manuelle ```
- Quick Start → Manual Explore
- Launch Browser
- Naviguer :
- Page d’accueil
- Recherche de produits
- Ajout au panier
- Processus de checkout
- Créer un compte
- Se connecter
-
Fermer le navigateur ```
-
Configurer l’authentification ```
- Context → Authentication → Form-Based
- Login URL: https://shop.exemple.com/login
- Trouver la requête POST de login dans History
- Flag as Context → Authentication Login Request
- Logged In Indicator: “My Account”
-
Add User: testuser / testpass123 ```
-
Spider automatique ```
- Clic droit sur site → Attack → Spider
- User: testuser
- Start Spider
-
Attendre la fin (100%) ```
-
AJAX Spider (pour le JS) ```
- Attack → AJAX Spider
- Start
-
Attendre la fin ```
-
Analyse passive ```
- Vérifier les alertes détectées passivement
- Alerts → Filtrer par Risk: High, Medium
-
Noter :
- Missing security headers
- Cookies without Secure flag
- Mixed content ```
-
Scan actif ciblé ```
- Clic droit sur /checkout → Active Scan
- User: testuser
- Policy: Default
- Start Scan
-
Répéter pour :
- /search
- /product/view
- /cart
- /payment ```
-
Tests manuels spécifiques
Test 1 : Manipulation de prix ``` Requête POST /cart/add : product_id=42&quantity=1&price=99.99
Modifier : product_id=42&quantity=1&price=0.01
Observer si le prix est validé côté serveur ```
Test 2 : Manipulation d’ID utilisateur ``` GET /orders/view?order_id=123&user_id=42
Modifier user_id pour voir les commandes d’autres utilisateurs ```
Test 3 : Bypass de paiement ``` POST /payment/process order_id=123&amount=99.99&status=pending
Modifier : order_id=123&amount=99.99&status=paid ```
-
Génération du rapport
Report → Generate HTML Report Title: "E-commerce Security Assessment" Include: All Alerts Generate -
Résultats attendus ``` High:
- SQL Injection in /search
- IDOR in /orders/view
- Price manipulation in /cart
Medium: - XSS in product reviews - CSRF in checkout - Weak session cookies
Low: - Missing X-Frame-Options - Cookie without SameSite ```
Scénario 2 : API REST mobile¶
Objectif : Tester l’API backend d’une application mobile.
Étapes :
- Configuration du proxy mobile ```
-
ZAP : Tools → Options → Local Proxies
- Address: 0.0.0.0 (écouter sur toutes les interfaces)
- Port: 8080
-
Sur le smartphone :
- WiFi Settings → Proxy Manual
- Server: [IP de votre PC] (ex: 192.168.1.100)
- Port: 8080
-
Installer le certificat ZAP sur le mobile :
- Naviguer vers http://192.168.1.100:8080
- Télécharger le certificat
- Installer (Settings → Security → Install from storage) ```
-
Capturer le trafic ```
- Utiliser l’application mobile normalement
- Observer toutes les requêtes API dans ZAP History
-
Identifier les endpoints :
- GET /api/v1/users/me
- POST /api/v1/auth/login
- GET /api/v1/products
- POST /api/v1/orders
- etc. ```
-
Analyse du mécanisme d’authentification ``` Requête de login : POST /api/v1/auth/login Content-Type: application/json
{“email”: “user@test.com”, “password”: “pass123”}
Réponse : { “token”: “eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9…”, “refresh_token”: “…”, “expires_in”: 3600 }
Requêtes suivantes : Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9… ```
- Tests JWT ```
- Installer JWT add-on
- Sélectionner une requête avec JWT
-
Show JWT → Observer le contenu : { “user_id”: 42, “email”: “user@test.com”, “role”: “user”, “exp”: 1234567890 }
-
Tester :
- Modification du user_id
- Modification du role (user → admin)
- Algorithme “none”
- Token expiré
- Token malformé ```
-
Énumération d’endpoints ```
- Forced Browse sur /api/v1/
-
Liste personnalisée : /api/v1/admin /api/v1/debug /api/v1/internal /api/v1/test /api/v1/swagger /api/v1/docs /api/v2/
-
Résultats : ✅ /api/v1/swagger (200 OK) → Documentation complète de l’API! ✅ /api/v1/admin (403 Forbidden) → Existe mais protégé ```
-
Import Swagger/OpenAPI ```
- Import → OpenAPI
- URL: https://api.exemple.com/api/v1/swagger.json
- Import
Tous les endpoints sont automatiquement ajoutés! ```
- Fuzzing des endpoints ``` GET /api/v1/users/42
Fuzzer “42” : - 1-1000 (énumération) - SQLi payloads - -1, 0, 99999999 - ../../../etc/passwd - ```
- Test de limites de taux (Rate Limiting) ```
- Requête : POST /api/v1/auth/login
- Resend 1000 fois rapidement
-
Observer :
- 429 Too Many Requests ? (✅ protégé)
- 200 OK toujours ? (❌ pas de protection) ```
-
Mass Assignment ``` POST /api/v1/users { “email”: “test@test.com”, “password”: “pass123” }
Tester : { “email”: “test@test.com”, “password”: “pass123”, “role”: “admin”, “is_verified”: true, “credits”: 99999 }
Observer si les champs supplémentaires sont acceptés ```
-
Rapport final ``` High:
- JWT signature not verified (algorithm “none” accepted)
- IDOR in /api/v1/users/{id}
- Mass assignment in user creation
Medium: - No rate limiting on authentication - Swagger documentation publicly accessible - Verbose error messages expose stack traces
Low: - API versioning in URL (should use headers) ```
Scénario 3 : Application avec 2FA¶
Objectif : Tester une application avec authentification à deux facteurs.
Méthode pour contourner/tester 2FA :
- Test de bypass direct ``` Étapes normales :
- POST /login → Redirect to /2fa
- POST /2fa/verify → Redirect to /dashboard
Test : 1. POST /login 2. Au lieu de /2fa, accéder directement à /dashboard 3. Observer si l’accès est autorisé (bypass!) ```
- Test de réutilisation de code ```
- Se connecter normalement
- Noter le code 2FA : 123456
- Se reconnecter
- Réutiliser le code : 123456
-
Observer si accepté (le code devrait être à usage unique) ```
-
Test de bruteforce ```
- Intercepter POST /2fa/verify
- Body: code=123456
- Fuzzer avec Numberzz : 000000-999999
-
Observer :
- Rate limiting ? (après X tentatives)
- Account lockout ?
- Bruteforce possible ? ```
-
Test du backup code ``` Si des codes de backup sont fournis :
- Utiliser un code de backup
- Réutiliser le même code
- Observer s’il est invalidé après usage ```
Scénario 4 : Scan en CI/CD¶
Objectif : Intégrer ZAP dans un pipeline CI/CD.
Workflow complet :
#!/bin/bash
# ci-zap-scan.sh
set -e
# Variables
TARGET_URL="http://staging.exemple.com"
ZAP_PORT=8080
REPORT_DIR="./zap-reports"
FAIL_ON_HIGH=true
echo "[*] Starting ZAP daemon..."
docker run -d --name zap \
-p ${ZAP_PORT}:${ZAP_PORT} \
-v $(pwd)/${REPORT_DIR}:/zap/wrk:rw \
zaproxy/zap-stable \
zap.sh -daemon -host 0.0.0.0 -port ${ZAP_PORT} \
-config api.disablekey=true
echo "[*] Waiting for ZAP to start..."
sleep 30
echo "[*] Running baseline scan..."
docker exec zap zap-baseline.py \
-t ${TARGET_URL} \
-r /zap/wrk/baseline-report.html \
-J /zap/wrk/baseline-report.json \
-c baseline.conf
echo "[*] Parsing results..."
HIGH_COUNT=$(docker exec zap python3 -c "
import json
with open('/zap/wrk/baseline-report.json') as f:
data = json.load(f)
high = sum(1 for alert in data['site'][0]['alerts'] if alert['riskcode'] == '3')
print(high)
")
echo "[+] Found ${HIGH_COUNT} high-risk alerts"
echo "[*] Stopping ZAP..."
docker stop zap && docker rm zap
# Fail le build si alertes high
if [ "$FAIL_ON_HIGH" = true ] && [ "$HIGH_COUNT" -gt 0 ]; then
echo "[!] Build failed: ${HIGH_COUNT} high-risk alerts found"
exit 1
fi
echo "[+] Scan completed successfully"
exit 0
Bonnes Pratiques et Éthique¶
Aspects légaux¶
⚠️ AVERTISSEMENT IMPORTANT ⚠️
L'utilisation de ZAP est soumise à des restrictions légales strictes :
✅ AUTORISÉ :
- Tests sur vos propres applications
- Pentests avec autorisation écrite
- Environnements de formation et CTF
- Recherche en sécurité avec permission
- Tests dans le cadre d'un Bug Bounty program
❌ INTERDIT :
- Tests sans autorisation explicite
- Scan de sites tiers sans permission
- Exploitation de vulnérabilités découvertes
- Accès non autorisé à des systèmes
- Exfiltration de données sans permission
Authorization et Documentation¶
Checklist avant un test :
□ Autorisation écrite obtenue et signée
□ Périmètre clairement défini (URLs, IPs)
□ Date et heure des tests convenus
□ Contact technique identifié
□ Contact d'urgence disponible
□ Limitations comprises (pas de DoS, etc.)
□ Backup des données effectué (si applicable)
□ Plan de communication établi
□ Assurance responsabilité professionnelle à jour
□ NDA signé si nécessaire
Document d’autorisation type :
# AUTORISATION DE TEST DE SÉCURITÉ
## Informations générales
- Date : [DATE]
- Client : [NOM DE L'ENTREPRISE]
- Testeur : [VOTRE NOM / ENTREPRISE]
- Période : Du [DATE DÉBUT] au [DATE FIN]
## Périmètre autorisé
### Applications web
- https://app.exemple.com
- https://api.exemple.com
- https://admin.exemple.com
### Exclusions
- https://exemple.com/payment/* (système de paiement tiers)
- https://exemple.com/analytics/* (Google Analytics)
## Types de tests autorisés
- ✅ Scan passif
- ✅ Scan actif
- ✅ Spider/Crawling
- ✅ Fuzzing
- ❌ DoS/DDoS
- ❌ Social engineering
- ❌ Attaques physiques
## Restrictions
- Tests pendant les heures creuses (22h-6h) uniquement
- Maximum 10 threads concurrents
- Prévenir 24h avant chaque test
- Arrêter immédiatement si problème détecté
## Contacts
- Contact technique : [NOM] - [EMAIL] - [TÉLÉPHONE]
- Contact urgence : [NOM] - [EMAIL] - [TÉLÉPHONE]
## Signatures
Client : _________________ Date : _________
Testeur : ________________ Date : _________
Minimiser l’impact¶
1. Limiter la charge serveur
Tools → Options → Active Scan
- Host per Scan: 1
- Concurrent Scans: 1
- Max Results to List: 100
Tools → Options → Connection
- Timeout: 30 seconds
- Max connections per host: 5
2. Éviter les tests destructifs
Analyze → Scan Policy Manager
- Désactiver :
- Persistent XSS (stockage de données)
- SQL Injection (utiliser des payloads safe)
- Remote File Include
- Server Side Include
3. Exclure les fonctionnalités sensibles
Context → Exclude from Context:
.*logout.*
.*delete.*
.*remove.*
.*drop.*
.*admin/reset.*
4. Planifier les scans
# Lancer ZAP à une heure précise (cron)
0 2 * * * /opt/zap/zap.sh -cmd -autorun /path/to/plan.yaml
# Uniquement pendant les weekends
0 2 * * 6 /opt/zap/zap.sh -cmd -autorun /path/to/plan.yaml
Gestion des faux positifs¶
Marquer comme faux positif :
1. Sélectionner une alerte
2. Clic droit → Mark as False Positive
3. Ajouter un commentaire expliquant pourquoi
Exporter/Importer les faux positifs :
Tools → Options → Alert Filters
- Add alert filter
- Rule: SQL Injection
- URL: http://exemple.com/safe-endpoint
- Action: False Positive
File → Properties → Export Alert Filters
Utile pour : - Réutiliser entre scans - Partager avec l’équipe - Automatiser les scans récurrents
Reporting professionnel¶
Structure recommandée d’un rapport :
# Rapport de Test de Sécurité Web
## 1. Résumé exécutif
- Période du test
- Périmètre
- Méthodologie
- Résumé des findings
- Recommandations principales
## 2. Vue d'ensemble
### 2.1 Objectifs
### 2.2 Périmètre
### 2.3 Limitations
### 2.4 Méthodologie
## 3. Résultats détaillés
### 3.1 Statistiques
- Total URLs scanned: 1,234
- Total Alerts: 45
- High: 3
- Medium: 12
- Low: 20
- Informational: 10
### 3.2 Vulnérabilités critiques
#### 3.2.1 SQL Injection (CVSS 9.8)
- **Description** : ...
- **Impact** : ...
- **Localisation** : ...
- **Preuve de concept** : ...
- **Recommandation** : ...
### 3.3 Vulnérabilités moyennes
### 3.4 Vulnérabilités basses
### 3.5 Informations
## 4. Recommandations
### 4.1 Court terme (0-30 jours)
### 4.2 Moyen terme (30-90 jours)
### 4.3 Long terme (90+ jours)
## 5. Conclusion
## 6. Annexes
- A. Méthodologie détaillée
- B. Screenshots
- C. Logs techniques
- D. Références (OWASP, CWE, CVE)
Formation continue¶
Ressources pour apprendre :
-
Environnements de pratique légaux - DVWA (Damn Vulnerable Web Application) - WebGoat (OWASP) - Juice Shop (OWASP) - bWAPP - Mutillidae - HackTheBox - TryHackMe - PentesterLab
-
Documentation officielle - https://www.zaproxy.org/docs/ - https://www.zaproxy.org/docs/desktop/start/ - https://www.zaproxy.org/docs/api/
-
Vidéos et tutoriels - OWASP ZAP YouTube Channel - Simon Bennetts (créateur de ZAP) talks - PentesterAcademy
-
Certifications - OSCP (Offensive Security Certified Professional) - CEH (Certified Ethical Hacker) - GWAPT (GIAC Web Application Penetration Tester) - OSWE (Offensive Security Web Expert)
Environnement de test local :
# Installer OWASP Juice Shop
docker run -d -p 3000:3000 bkimminich/juice-shop
# Configurer ZAP pour le tester
# URL: http://localhost:3000
# 100% légal et safe!
Conclusion¶
OWASP ZAP est un outil extrêmement puissant et versatile pour la sécurité des applications web. Sa gratuité, son extensibilité, et son intégration CI/CD en font un choix excellent tant pour les débutants que les experts.
Points clés à retenir¶
- Toujours obtenir une autorisation avant tout test
- Commencer par du passif (sans risque)
- Progresser vers l’actif avec prudence
- Combiner automatisation et tests manuels pour de meilleurs résultats
- Documenter méticuleusement toutes les vulnérabilités
- Minimiser l’impact sur les systèmes testés
- Former continuellement vos compétences
Workflow recommandé¶
1. Configuration (Context, Scope, Auth)
↓
2. Exploration (Manual + Spider + AJAX Spider)
↓
3. Analyse passive (détection sans risque)
↓
4. Tests manuels ciblés (interception, modification)
↓
5. Scan actif (automatisé mais invasif)
↓
6. Fuzzing (tests approfondis)
↓
7. Validation manuelle (éliminer faux positifs)
↓
8. Reporting (documentation complète)
Aller plus loin¶
Après avoir maîtrisé ZAP : - Approfondir l’exploitation manuelle - Apprendre le développement sécurisé - Explorer d’autres outils (Burp Suite Pro, Acunetix, etc.) - Participer à des Bug Bounty programs - Contribuer au projet OWASP ZAP
Version du document : 1.0 Dernière mise à jour : 2025 Auteur : Guide complet OWASP ZAP
Avertissement : Ce document est fourni à des fins éducatives uniquement. L’auteur et les distributeurs ne peuvent être tenus responsables de toute utilisation illégale ou non éthique de ces informations. Toujours obtenir une autorisation écrite avant de tester la sécurité d’un système.