| name | api-automation-pipeline |
| description | Guide complet d'automatisation de pentest API — pipelines CI/CD, nuclei templates, custom scanners, Burp automation, Postman-to-Burp workflows, rapport génération, monitoring continu, et workflows intégrés |
| category | cybersecurite |
API Automation Pipeline — Guide Avancé
Introduction
L'automatisation est clé pour tester les API en continu : intégration CI/CD, templates reproductibles, scripts custom, et génération de rapports. Ce skill couvre la construction d'un pipeline complet de sécurité API.
1. Nuclei — Templates API
1.1 Template Basique
id: api-healthcheck
info:
name: API Health Check
severity: info
tags: api,info
http:
- method: GET
path:
- "{{BaseURL}}/health"
- "{{BaseURL}}/healthz"
- "{{BaseURL}}/status"
- "{{BaseURL}}/api/v1/health"
matchers:
- type: word
words:
- "ok"
- "healthy"
- "alive"
condition: or
1.2 Template BOLA/IDOR
id: api-bola-check
info:
name: API BOLA Check
severity: high
tags: api,bola,idor
http:
- method: GET
path:
- "{{BaseURL}}/api/v1/users/1"
- "{{BaseURL}}/api/v1/users/2"
- "{{BaseURL}}/api/v1/users/3"
- "{{BaseURL}}/api/v1/users/admin"
headers:
Authorization: "Bearer {{token}}"
matchers-condition: and
matchers:
- type: status
status:
- 200
- type: word
words:
- "email"
- "role"
- "admin"
condition: or
1.3 Template Mass Assignment
id: api-mass-assignment
info:
name: API Mass Assignment Check
severity: high
tags: api,mass-assignment
http:
- method: POST
path:
- "{{BaseURL}}/api/v1/users/signup"
- "{{BaseURL}}/api/v1/auth/signup"
headers:
Content-Type: application/json
body: '{"username":"test{{randstr}}","password":"test123","isAdmin":true,"role":"admin"}'
matchers-condition: and
matchers:
- type: status
status:
- 200
- 201
- type: word
words:
- "isAdmin"
- "admin"
- "role"
1.4 Template Shadow API
id: api-shadow-discovery
info:
name: API Shadow Endpoint Discovery
severity: medium
tags: api,shadow
http:
- method: GET
path:
- "{{BaseURL}}/swagger.json"
- "{{BaseURL}}/openapi.json"
- "{{BaseURL}}/api-docs"
- "{{BaseURL}}/graphql"
- "{{BaseURL}}/v2/api-docs"
- "{{BaseURL}}/api/v2/users"
- "{{BaseURL}}/api/v3/users"
- "{{BaseURL}}/admin"
- "{{BaseURL}}/debug"
- "{{BaseURL}}/internal"
matchers:
- type: status
status:
-
1.5 Template avec Extraction
id: api-secret-leak
info:
name: API Secret Leak Response
severity: critical
tags: api,secrets
http:
- method: GET
path:
- "{{BaseURL}}/api/v1/config"
- "{{BaseURL}}/api/v1/env"
- "{{BaseURL}}/.env"
- "{{BaseURL}}/debug"
extractors:
- type: regex
regex:
- "(?:ASIA|AKIA)[A-Z0-9]{16}"
- "ghp_[a-zA-Z0-9]{36}"
- "sk-[a-zA-Z0-9]{32,}"
- "xox[baprs]-[a-zA-Z0-9-]{10,}"
2. Pipeline CI/CD Complet
2.1 GitHub Actions
name: API Security Scan
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
jobs:
api-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install tools
run: |
go install github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
go install github.com/ffuf/ffuf/v2@latest
pip install requests httpx
- name: Nuclei API scan
run: |
nuclei -u ${{ secrets.API_URL }} \
-t nuclei-templates/api/ \
-H "Authorization: Bearer ${{ secrets.API_TOKEN }}" \
-severity critical,high,medium \
-o api_vulns.txt \
-json -silent
- name: Rate limit test
run: |
python3 scripts/test_rate_limit.py \
--url ${{ secrets.API_URL }} \
--token ${{ secrets.API_TOKEN }}
- name: Generate report
run: |
python3 scripts/generate_report.py \
--input api_vulns.txt \
--output report.html
2.2 GitLab CI
api-security:
stage: security
image: kalilinux/kali-rolling
script:
- apt-get update && apt-get install -y nuclei ffuf python3-pip
- pip3 install requests
- nuclei -u $API_URL -t nuclei-templates/api/ \
-H "Authorization: Bearer $API_TOKEN" -severity critical,high
- ffuf -u $API_URL/api/v1/users/FUZZ -w ids.txt -fc 404
artifacts:
paths:
- nuclei_report.json
only:
- schedules
3. Scripts d'Automatisation
3.1 Scan Complet Multi-Outil
"""Pipeline de scan API automatisé complet."""
import subprocess
import json
import os
import argparse
from datetime import datetime
class APIScanner:
def __init__(self, base_url, token):
self.base_url = base_url.rstrip('/')
self.token = token
self.results = {"critical": [], "high": [], "medium": [], "low": [], "info": []}
def nuclei_scan(self):
"""Scan Nuclei avec templates API."""
print("[*] Nuclei scan...")
cmd = [
"nuclei", "-u", self.base_url,
"-t", "nuclei-templates/api/",
"-H", f"Authorization: Bearer {self.token}",
"-json", "-silent", "-severity", "critical,high,medium"
]
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
for line in result.stdout.strip().split('\n'):
if line:
:
vuln = json.loads(line)
severity = vuln.get(, {}).get(, )
.results[severity].append(vuln)
:
()
():
()
cmd = [
, , ,
, ,
, ,
, , , , , ,
]
subprocess.run(cmd, timeout=)
():
endpoints = [
, , ,
, , , ,
, , ,
, , ,
]
requests
ep endpoints:
:
r = requests.get(.base_url + ep, timeout=,
headers={: })
r.status_code [, ]:
()
:
():
now = datetime.now().strftime()
html =
sev [, , ]:
v .results[sev]:
info = v.get(, {})
html +=
html +=
html +=
html +=
os.makedirs(, exist_ok=)
path =
(path, ) f:
f.write(html)
()
path
__name__ == :
parser = argparse.ArgumentParser()
parser.add_argument(, required=)
parser.add_argument(, required=)
args = parser.parse_args()
scanner = APIScanner(args.url, args.token)
scanner.nuclei_scan()
scanner.ffuf_scan()
scanner.check_shadow_endpoints()
scanner.generate_report()
3.2 Postman Collection Automation
npm install -g newman
newman run api-tests.postman_collection.json \
--env-var "base_url=https://api.target.com" \
--env-var "token=Bearer <token>" \
--reporters cli,json \
--reporter-json-export newman_report.json
newman run api-security.postman_collection.json \
--env-var "base_url=https://api.target.com" \
--timeout-request 5000 \
--delay-request 100 \
--bail
3.3 Burp Automation (Headless)
docker run --rm -v $(pwd):/output \
public.ecr.aws/portswigger/dastardly:latest \
https://api.target.com
curl -X POST http://127.0.0.1:1337/v0.1/scan \
-H "Content-Type: application/json" \
-d '{
"urls": ["https://api.target.com"],
"name": "API Scan",
"scope": {"include": [{"rule": "https://api.target.com/*"}]}
}'
curl http://127.0.0.1:1337/v0.1/scan/<scan_id>
4. Continuous Monitoring
4.1 Cron Job de Scan
0 6 * * * cd /opt/api-scanner && python3 scan.py --url https://api.target.com --token $TOKEN
0 6 * * * cd /opt/api-scanner && python3 scan.py --url https://api.target.com --token $TOKEN \
&& python3 notify.py
4.2 Webhook-Based Monitoring
"""Moniteur API continu via webhook."""
import requests
import hashlib
import json
from time import sleep
BASE = "https://api.target.com"
TOKEN = "Bearer <token>"
known_endpoints = set()
def discover_endpoints():
"""Découvre les endpoints API courants."""
endpoints = [
"/api/v1/users/1",
"/api/v1/products/1",
"/api/v1/orders/1",
"/api/v1/health",
"/api/v1/admin/users",
"/openapi.json",
"/swagger.json",
]
for ep in endpoints:
try:
r = requests.get(BASE + ep, headers={"Authorization": TOKEN}, timeout=5)
if r.status_code != 404:
known_endpoints.add(ep)
content_hash = hashlib.md5(r.text.encode()).hexdigest()
print(f"[INFO] {ep}: {r.status_code} | hash={content_hash[:8]}")
except:
pass
def check_changes():
"""Vérifie si un nouveau endpoint apparaît."""
new_endpoints = ["/api/v4/users/1", "/internal/v2/admin", "/api/v2/users/1"]
ep new_endpoints:
:
r = requests.get(BASE + ep, headers={: TOKEN}, timeout=)
r.status_code != ep known_endpoints:
()
requests.post(,
json={: })
:
__name__ == :
:
discover_endpoints()
check_changes()
sleep()
5. Résumé des Outils par Phase
| Phase | Outil | Usage |
|---|
| Recon | nuclei, katana, waybackpy | Découverte endpoints |
| Fuzzing | ffuf, arjun, wfuzz | Paramètres, valeurs |
| Auth | jwt_tool, Autorize | BOLA, JWT, ACL |
| Injection | sqlmap, graphqlmap | SQL, NoSQL, injection |
| Automation | newman, dastardly | Postman, Burp headless |
| CI/CD | GitHub Actions, GitLab CI | Scan automatisé |
| Report | nuclei -json, custom scripts | Génération rapports |
Checklist
Ressources