Rappel théorique
Une faille SSRF (Server-Side Request Forgery) survient lorsqu'une
application effectue une requête réseau vers une URL fournie ou influencée par
l'utilisateur, sans en contrôler la destination. Le serveur agit alors comme un
proxy involontaire pour l'attaquant : celui-ci peut faire interroger par le serveur des
ressources normalement inaccessibles depuis l'extérieur (réseau interne, services
d'administration, métadonnées cloud, localhost...).
Exemple de code vulnérable
// "Aperçu d'URL" ou "import depuis une URL"
$contenu = file_get_contents($_GET['url']);
echo $contenu;
Un attaquant peut alors fournir ?url=http://127.0.0.1/admin pour faire
afficher par le serveur une page d'administration interne qu'il ne pourrait pas
atteindre directement.
Cibles classiques d'une SSRF
http://127.0.0.1/...ouhttp://localhost/...- services internes au serveur lui-même.- Réseau interne de l'hébergeur (
10.x.x.x,172.16-31.x.x,192.168.x.x) - bases de données, API internes. - Métadonnées des fournisseurs cloud (ex. AWS :
http://169.254.169.254/latest/meta-data/) pouvant exposer des identifiants temporaires.
Mesures de protection
- Liste blanche de domaines/protocoles autorisés (uniquement
http/httpsvers des hôtes connus). - Résoudre le nom d'hôte en adresse IP et vérifier qu'elle n'appartient pas à
une plage privée ou réservée avec
filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)(bloque127.0.0.0/8,10.0.0.0/8,192.168.0.0/16,169.254.0.0/16...). - Ne pas suivre les redirections HTTP automatiquement (un hôte autorisé pourrait rediriger vers une cible interne).
- Isoler réseau-iquement les services internes sensibles (segmentation, pare-feu) - défense en profondeur.
Démo vulnérable
Un "lecteur d'URL" qui récupère et affiche le contenu de n'importe quelle URL avec
file_get_contents($_GET['url']).
Démo sécurisée
Même fonctionnalité, mais l'URL est validée : protocole autorisé, et adresse IP résolue vérifiée pour exclure les plages privées/réservées.
Service interne simulé
internal_admin.php simule un service d'administration
interne (jeton d'API, statistiques). Dans ce TP local, il est servi par le même Apache
que le reste de l'application - en production, il serait sur un hôte/port non exposé sur
Internet, mais atteignable par le serveur applicatif via 127.0.0.1 ou le
réseau interne.