Comment obtenir l'adresse IP source d'une requête http sur un serveur web présent derrière un reverse-proxy ?
1. Préambule
Un proxy inverse (reverse-proxy) est un type de serveur, habituellement placé en frontal des serveurs web. Ainsi, le client web passe par cet intermédiaire pour accéder aux applications des serveurs internes. Le reverse-proxy peut fournir différentes fonctionnalités intéressantes comme une fonction de cache, des fonctions de répartition de charges, des fonctions de sécurité (WAF), le chiffrement TLS et la compression.
2. Introduction
Si vous fonctionnez dans une architecture où vous disposez d’un reverse-proxy situé en amont de vos serveurs applicatifs classiques, alors vous avez certainement remarqué que l’adresse IP source présente dans les fichiers journaux de vos serveurs applicatifs est celle de votre serveur mandataire inversé et non celle du client réel.
anakin@tatooine:~$ sudo cat /var/log/apache2/access.log
192.0.2.10 - - [05/Feb/2019:00:00:40 +0100] "GET / HTTP/1.0" 200 6458
Nous constatons dans l’exemple précédent que l’adresse IP indiquée est celle du serveur mandataire inverse et non celle de la source réel de la requête http. Heureusement, le reverse-proxy peut générer deux en-têtes http permettant de fournir aux serveurs web présents en arrière-plan l’adresse IP de l’émetteur de la requête http originale : X-Forwarded-For et X-Real-IP.
Le RFC 7239 définit plus précisément le fonctionnement du mécanisme Forwarded. À noter qu’il existe également un en-tête Forwarded qui permettrait d’ajouter un mécanisme d’authentification (token) qui garantirait l’identité du reverse-proxy. X-Forwarded-For fournit l’adresse IP du client d’origine ainsi que l’adresse des différents répartiteurs de charge ou serveurs mandataires inversés sollicités. Concernant l’en-tête X-Real-IP, je n’ai pas trouvé d’informations précises sur son mode de fonctionnement. Il semblerait qu’il permette de fournir l’adresse IP du client qui est pour le reverse-proxy, l’hôte qui lui a envoyé la requête.
3. Configurations
a. Le reverse-proxy
Dans un premier temps, il est nécessaire de configurer le reverse-proxy (basé ici sur nginx) afin qu’il ajoute les en-têtes nécessaires aux requêtes http qu’il transmettra aux serveurs web situés en arrière-plan. Ces derniers pourront ainsi utiliser l’une des deux en-têtes pour récupérer l’adresse IP réelle de l’émetteur.
vador@mustafar:~$ sudo nano /etc/nginx/sites-available/reverse
location / {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
b. Le cas d’un serveur Apache en arrière-plan
Dans un second temps, nous allons nous occuper des serveurs situés à l’arrière-plan. Si vous diposez de serveurs fonctionnant avec le service Apache alors voici les différentes étapes nécessaires pour permettre à celui-ci de récupérer l’information désirée :
anakin@tatooine:~$ sudo a2enmod remoteip
Puis nous allons configurer ce module :
anakin@tatooine:~$ sudo nano /etc/apache2/conf-available/remoteip.conf
RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 192.0.2.10
anakin@tatooine:~$ sudo a2enconf remoteip
Nous allons maintenant spécifié dans la configuration globale du service web que nous souhaitons que ce soit l’adresse IP du client et non du serveur mandataire inversé qui soient pris en compte dans les logs :
anakin@tatooine:~$ sudo nano /etc/apache2/apache2.conf
LogFormat "%v:%p %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %O" common
Ici l’important est le %a. Si l’on s’en réfère à la documentation officielle de Apache 2, cette variable permet d’afficher l’adresse IP distante et non celle du reverse-proxy dans les fichiers journaux.
Enfin il est nécessaire de recharger la configuration de notre service Apache :
anakin@tatooine:~$ sudo systemctl reload apache2
Un petit tour dans les logs du serveur :
anakin@tatooine:~$ sudo cat /var/log/apache2/access.log
69.89.31.134 - - [05/Feb/2019:00:00:40 +0100] "GET / HTTP/1.0" 200 6458
c. Le cas d’un serveur nginx en arrière-plan
Il se peut que vous ayez plutôt un autre service nginx en arrière-plan. Dans ce cas, la configuration n’est pas la même que celle du service Apache. Voici les étapes nécessaires si vous avez fait le choix d’utiliser ce service :
yoda@dagobah:~$ sudo nano /etc/nginx/nginx.conf
log_format specialLog '$remote_addr forwarded for $http_x_real_ip - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
yoda@dagobah:~$ sudo systemctl reload nginx
Un petit tour dans les logs du serveur :
yoda@dagobah:~$ sudo cat /var/log/nginx/access.log
69.89.31.134 forwarded for 69.89.31.134 - - [05/Feb/2019:00:00:40 +0100] "GET / HTTP/1.1" 200 728 "-" "-"
4. Conclusion
Voilà ! Si vous avez des remarques, des corrections ou des précisions à apporter sur mon article, n’hésitez pas ! Ce sera avec plaisir que je les prendrai en compte.
Enjoy :D