Introduction : pourquoi « simple REMOTE_ADDR » ne fonctionne plus
Chaque développeur PHP s'est au moins une fois demandé : « Comment obtenir l'adresse IP du client ? ». Sur Stack Overflow, ce sujet cumule des centaines de milliers de vues, et la réponse canonique est accompagnée de dizaines de commentaires de clarification. Le problème est qu'en 2025, le simple $_SERVER['REMOTE_ADDR'] ne suffit plus.
Les sites modernes vivent derrière des CDN (Cloudflare, Akamai), des répartiteurs de charge et des serveurs proxy. Les utilisateurs se connectent via VPN ou Tor. Et les attaquants ont appris à falsifier les en-têtes. Si vous voulez connaître la véritable adresse IP du visiteur — sans pour autant ouvrir la porte aux attaques — vous devez appliquer des pratiques éprouvées.
Dans cet article, je vais montrer comment fonctionne la détermination de l'IP en PHP, analyser les pièges et fournir un code prêt à l'emploi que vous pouvez utiliser en toute confiance en 2025.
Comment PHP « voit » l'adresse IP ?
Lorsque le navigateur envoie une requête au serveur, PHP remplit automatiquement le tableau superglobal $_SERVER. La clé REMOTE_ADDR est responsable de l'adresse IP de « l'interlocuteur ». Dans un monde idéal (sans proxy), c'est l'IP du client :
<?php$ip = $_SERVER['REMOTE_ADDR']; // 192.168.1.5?>Mais en réalité, derrière le serveur se trouve souvent nginx, HAProxy ou Cloudflare. Alors REMOTE_ADDR affiche l'IP du proxy, et non celle de l'utilisateur. L'adresse authentique est transmise dans les en-têtes HTTP :
HTTP_X_FORWARDED_FOR— en-tête standard pour les proxy ;HTTP_X_REAL_IP— utilisé par nginx ;HTTP_CF_CONNECTING_IP— spécifique à Cloudflare ;HTTP_CLIENT_IP— rare, mais existe.
Problème : n'importe lequel de ces en-têtes peut être falsifié. Si vous faites confiance à $_SERVER['HTTP_X_FORWARDED_FOR'] sans vérification, un attaquant peut facilement substituer une autre IP.
REMOTE_ADDR contre X-Forwarded-For : quand utiliser quoi ?
Voici la règle clé qui vous évitera bien des maux de tête :
- Si le site est directement sur le serveur sans proxy — utilisez uniquement
REMOTE_ADDR. - Si le site est derrière un proxy de confiance (CDN, répartiteur de charge) — prenez l'IP de l'en-tête, mais seulement après avoir vérifié que la requête provient bien de votre proxy.
En 2025, le standard de facto est X-Forwarded-For. Il peut contenir une chaîne d'IP : client, proxy1, proxy2. La première adresse est celle du client, la dernière est celle du dernier proxy.
Pourquoi ne pas faire aveuglément confiance à X-Forwarded-For ?
Imaginez : un attaquant envoie une requête avec l'en-tête X-Forwarded-For: 127.0.0.1. Si votre code lit simplement $_SERVER['HTTP_X_FORWARDED_FOR'], vous obtiendrez 127.0.0.1 (hôte local). Les logs, l'analytique, la géolocalisation — tout sera cassé. Pire encore, l'attaquant peut substituer l'IP d'un autre utilisateur pour se faire passer pour lui.
Solution : ne faire confiance à l'en-tête X-Forwarded-For que si REMOTE_ADDR est égal à l'IP de votre proxy de confiance. Pas autrement.
Meilleure pratique 2025 : fonction universelle d'obtention de l'IP
J'ai rassemblé une logique éprouvée qui prend en compte toutes les réalités modernes. La fonction :
- Vérifie si la requête passe par des proxy de confiance (vous définissez leur liste).
- Si oui — extrait la première IP de
X-Forwarded-For. - Si non — retourne
REMOTE_ADDR. - Filtre les adresses privées et réservées (optionnel).
<?php/** * Obtient l'adresse IP réelle du client. * * @param array $trustedProxies Liste des IP de proxy de confiance * @return string Adresse IP ou '0.0.0.0' si impossible à déterminer */function getClientIP(array $trustedProxies = []): string { $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';