first commit
This commit is contained in:
parent
883dd76931
commit
2e22667181
17 changed files with 889 additions and 5 deletions
36
tools/api-fuzzer/README.md
Normal file
36
tools/api-fuzzer/README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# api-fuzzer
|
||||
|
||||
Cartographie la surface d'API des trois hôtes preprod (Org, Api,
|
||||
Blogs) : codes de réponse par endpoint, verbes autorisés (via
|
||||
`OPTIONS` + en-tête `Allow`), fuites d'information dans les erreurs
|
||||
500.
|
||||
|
||||
## Principe
|
||||
|
||||
Lit une liste de chemins dans `endpoints.txt` (modifiable) et, pour
|
||||
**chaque hôte du périmètre** (`TARGET_BASE_URL` + `TARGET_ALLOWED_HOSTS`),
|
||||
émet `GET` puis `OPTIONS`. Journalise le code, la taille du corps et
|
||||
les verbes autorisés.
|
||||
|
||||
## Lancement
|
||||
|
||||
```bash
|
||||
./fuzz.sh
|
||||
# ou avec une liste d'endpoints personnalisée :
|
||||
./fuzz.sh targets.env mes-endpoints.txt
|
||||
```
|
||||
|
||||
## Sortie
|
||||
|
||||
- stdout : endpoints notables (200 accessible, 500 fuite possible).
|
||||
- `output/api-fuzz.log` : une ligne par test
|
||||
(`horodatage \t GET \t base \t code \t taille \t chemin`).
|
||||
|
||||
## Actions typiques
|
||||
|
||||
- Endpoint renvoyant 500 avec une stack trace → fuite d'info : activer
|
||||
`UseExceptionHandler` en prod, masquer les détails.
|
||||
- `OPTIONS` révèle `DELETE`/`PUT` sur une route qu'on croyait GET-only
|
||||
→ vérifier l'autorisation côté serveur (les verbes ne devraient pas
|
||||
dépendre que du routage).
|
||||
- Endpoint non documenté en 200 → inventorier et fermer si inutile.
|
||||
34
tools/api-fuzzer/endpoints.txt
Normal file
34
tools/api-fuzzer/endpoints.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# endpoints.txt — liste de chemins à énumérer (un par ligne).
|
||||
# Lignes vides et commençant par # sont ignorées.
|
||||
# Adaptez à la surface d'API d'Yavsc (voir docs/scope.md).
|
||||
# Tout chemin est préfixé par TARGET_BASE_URL.
|
||||
|
||||
# --- Auth / IdentityServer ---
|
||||
/account/login
|
||||
/account/register
|
||||
/account/forgotpassword
|
||||
/connect/token
|
||||
/connect/authorize
|
||||
/connect/userinfo
|
||||
/connect/logout
|
||||
/.well-known/openid-configuration
|
||||
/.well-known/jwks
|
||||
|
||||
# --- API business (host API, si exposé via la même preprod) ---
|
||||
/api/v1/estimate
|
||||
/api/v1/front/query
|
||||
/api/v1/activity
|
||||
/api/v1/profiles
|
||||
|
||||
# --- Blogs / FS ---
|
||||
/api/v1/fs
|
||||
/api/v1/blogs
|
||||
|
||||
# --- Surfaces de doc / debug ---
|
||||
/swagger
|
||||
/swagger/index.html
|
||||
/swagger/v1/swagger.json
|
||||
/openapi.json
|
||||
/health
|
||||
/healthz
|
||||
/diagnostics
|
||||
83
tools/api-fuzzer/fuzz.sh
Executable file
83
tools/api-fuzzer/fuzz.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
|||
#!/usr/bin/env bash
|
||||
# fuzz.sh — énumère les endpoints d'une API et cartographie les codes
|
||||
# de réponse, pour repérer les routes ouvertes, les fuites d'info dans
|
||||
# les messages d'erreur, et les variations de comportement.
|
||||
#
|
||||
# USAGE
|
||||
# ./fuzz.sh [targets.env] [endpoints.txt]
|
||||
#
|
||||
# Lit une liste de chemins (un par ligne) depuis le 2e argument, sinon
|
||||
# FUZZ_PATHS, sinon ./endpoints.txt à côté du script. Pour chaque
|
||||
# chemin, émet GET et OPTIONS (pour détecter les verbes autorisés via
|
||||
# l'en-tête Allow).
|
||||
#
|
||||
# Journalise dans $OUTPUT_DIR/api-fuzz.log.
|
||||
|
||||
COMMON_SH="$(cd "$(dirname "$0")/../.." && pwd)/lib/common.sh"
|
||||
# shellcheck disable=SC1091
|
||||
source "$COMMON_SH"
|
||||
load_target "${1:-}"
|
||||
|
||||
LIST="${2:-${FUZZ_PATHS:-$(dirname "$0")/endpoints.txt}}"
|
||||
[[ -f "$LIST" ]] \
|
||||
|| die "Liste d'endpoints introuvable : $LIST (créez endpoints.txt ou réglez FUZZ_PATHS)"
|
||||
|
||||
mkdir -p "${OUTPUT_DIR:-./output}"
|
||||
LOG="${OUTPUT_DIR:-./output}/api-fuzz.log"
|
||||
: > "$LOG"
|
||||
|
||||
info "Fuzz de $(wc -l < "$LIST") endpoints sur ${#AUTHORIZED_HOSTS[@]} hôte(s) du périmètre"
|
||||
info "Liste : $LIST"
|
||||
info "Journal : $LOG"
|
||||
|
||||
# Endpoints **intentionnellement publics** : un 200 dessus est normal,
|
||||
# pas une anomalie. Ex : la discovery OIDC d'IdentityServer, que les
|
||||
# clients (PostIt) interrogent pour découvrir les endpoints d'auth.
|
||||
EXPECTED_PUBLIC=(
|
||||
"/.well-known/openid-configuration"
|
||||
"/.well-known/jwks"
|
||||
)
|
||||
is_expected_public() {
|
||||
local p="$1"
|
||||
local e
|
||||
for e in "${EXPECTED_PUBLIC[@]}"; do [[ "$e" == "$p" ]] && return 0; done
|
||||
return 1
|
||||
}
|
||||
|
||||
while IFS= read -r base; do
|
||||
info "→ $base"
|
||||
while IFS= read -r p || [[ -n "$p" ]]; do
|
||||
[[ -z "$p" || "$p" == \#* ]] && continue
|
||||
url="${base}${p}"
|
||||
http_probe GET "$url"
|
||||
code="$LAST_CODE"
|
||||
size=0
|
||||
[[ -n "$LAST_BODY" && -s "$LAST_BODY" ]] && size=$(wc -c < "$LAST_BODY")
|
||||
printf '%s\tGET\t%s\t%s\t%8d\t%s\n' "$(date -Is)" "$base" "$code" "$size" "$p" >> "$LOG"
|
||||
|
||||
# Verbes autorisés : la réponse à OPTIONS peut révéler POST/DELETE
|
||||
# même sur une route GET-only côté serveur.
|
||||
allow="$(set +e; curl -s -D - -o /dev/null -X OPTIONS \
|
||||
--connect-timeout "${CURL_TIMEOUT:-10}" --max-time "${CURL_MAX_TIME:-30}" \
|
||||
"$url" | tr -d '\r' | awk -F': ' 'tolower($1)=="allow"{print $2}')"
|
||||
[[ -n "$allow" ]] && printf '%s\tOPT\t%s\tAllow: %s\t%s\n' "$(date -Is)" "$base" "$allow" "$p" >> "$LOG"
|
||||
|
||||
case "$code" in
|
||||
200)
|
||||
if is_expected_public "$p"; then
|
||||
ok "200 $base$p — public attendu (OIDC discovery)"
|
||||
else
|
||||
warn "200 $base$p — accessible"
|
||||
fi
|
||||
;;
|
||||
401|403) ;;
|
||||
404) ;;
|
||||
500) err "500 $base$p — erreur serveur (fuite d'info possible)" ;;
|
||||
*) warn "$code $base$p" ;;
|
||||
esac
|
||||
drop_body
|
||||
pace
|
||||
done < "$LIST"
|
||||
done < <(each_scope_url)
|
||||
|
||||
info "Terminé. Voir $LOG."
|
||||
Loading…
Add table
Add a link
Reference in a new issue