nginx real_ip_header et X-Forwarded-For semblent incorrects

59

La description de Wikipédia de l'en-tête HTTP X-Forwarded-Forest la suivante:

X-Forwarded-For: client1, proxy1, proxy2, ...

La documentation de la directive nginx se real_ip_headerlit notamment:

Cette directive définit le nom de l'en-tête utilisé pour transférer l'adresse IP de remplacement.
Dans le cas de X-Forwarded-For, ce module utilise la dernière adresse IP de l'en-tête X-Forwarded-For pour le remplacement. [Souligne moi]

Ces deux descriptions semblent en contradiction. Dans notre scénario, l'en- X-Forwarded-Fortête correspond exactement à la description. L'adresse IP "réelle" du client est l'entrée la plus à gauche. De même, le comportement de nginx consiste à utiliser la valeur la plus à droite - qui, de toute évidence, n’est qu’un de nos serveurs proxy.

D'après ce que je comprends, X-Real-IPcela est censé être utilisé pour déterminer l' adresse IP réelle du client, et non le proxy. Est-ce que quelque chose me manque ou est-ce un bogue dans nginx?

Et, au-delà de cela, est-ce que quelqu'un a des suggestions sur la manière de rendre l'en- X-Real-IPtête afficher la valeur la plus à gauche , comme indiqué par la définition de X-Forwarded-For?

Kirk Woll
la source

Réponses:

97

Je crois que la solution à la configuration récemment introduite real_ip_recursive(ajoutée dans nginx 1.2.1 et 1.3.0) est la solution pour résoudre les problèmes liés à X-Forwarded-For lorsque plusieurs adresses IP sont chaînées . Dans les documents nginx realip :

Si la recherche récursive est activée, une adresse de client d'origine correspondant à l'une des adresses de confiance est remplacée par la dernière adresse non de confiance envoyée dans le champ d'en-tête de la demande.

nginx récupérait par défaut la dernière adresse IP de la chaîne, car c’était la seule adresse supposée fiable. Mais avec la nouvelle option real_ip_recursiveactivée et avec plusieurs set_real_ip_fromoptions, vous pouvez définir plusieurs proxys de confiance et la dernière adresse IP récupérée.

Par exemple, avec cette config:

set_real_ip_from 127.0.0.1;
set_real_ip_from 192.168.2.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

Et un en-tête X-Forwarded-For ayant pour résultat:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx choisira maintenant 123.123.123.123 comme adresse IP du client.

Quant à savoir pourquoi nginx ne choisit pas uniquement l'adresse IP la plus à gauche et vous oblige à définir explicitement les proxys de confiance, c'est pour éviter toute usurpation d'adresse IP facile.

Disons que la véritable adresse IP d'un client est 123.123.123.123. Disons également que le client ne fait rien et qu'il essaie de falsifier son adresse IP 11.11.11.11. Ils envoient une demande au serveur avec cet en-tête déjà en place:

X-Forwarded-For: 11.11.11.11

Comme les proxys inversés ajoutent simplement des adresses IP à cette chaîne X-Forwarded-For, disons que cela ressemble à ceci lorsque nginx y parvient:

X-Forwarded-For: 11.11.11.11, 123.123.123.123, 192.168.2.1, 127.0.0.1

Si vous saisissiez simplement l'adresse la plus à gauche, le client pourrait facilement usurper son adresse IP. Mais avec l'exemple ci-dessus, nginx config, nginx ne fera confiance qu'aux deux dernières adresses en tant que mandataires. Cela signifie que nginx choisira correctement 123.123.123.123l'adresse IP, même si cette adresse IP usurpée est la plus à gauche.

Nick M
la source
2
Merci beaucoup pour cela, cela m'a vraiment aidé. Cela devrait être la réponse acceptée.
José F. Romaniello
1
Par défaut, real_ip_header semble être X-Real-IP selon nginx.org/en/docs/http/ngx_http_realip_module.html Cela signifie-t-il qu'un utilisateur malveillant peut simplement envoyer une requête aléatoire avec X-Real-IP, qui sera utilisée comme $ remote_addr dans nginx (et éventuellement éventuellement passé à l'application)?
Gansbrest
@gansbrest Non, car set_real_ip_from limite les hôtes approuvés.
El Yobo
9

L’analyse de l’en- X-Forwarded-Fortête est en effet erronée dans le module nginx real_ip.

len = r->headers_in.x_forwarded_for->value.len;
ip = r->headers_in.x_forwarded_for->value.data;

for (p = ip + len - 1; p > ip; p--) {
  if (*p == ' ' || *p == ',') {
    p++;
    len -= p - ip;
    ip = p;
    break;
  }
}

Il commence à l'extrême droite de la chaîne d'en-tête et dès qu'il voit un espace ou une virgule, il cesse de regarder et colle la partie à droite de l'espace ou une virgule dans la variable IP. Ainsi, il traite l' adresse de proxy la plus récente comme l' adresse du client d'origine .

Il ne joue pas bien selon la spécification; c'est le danger de ne pas l'avoir énoncé en termes douloureusement évidents dans un RFC.

De plus: il est difficile de trouver même une bonne source primaire sur le format, qui avait été défini à l'origine par Squid - une fouille dans la documentation confirme la commande; le plus à gauche est le client d'origine, le plus à droite l'ajout le plus récent. Je suis extrêmement tenté d'ajouter une [citation nécessaire] à cette page wikipedia. Une édition anonyme semble être l'autorité d'Internet sur le sujet.

Si possible, pouvez-vous demander à vos mandataires intermédiaires de ne plus s'ajouter eux-mêmes à la fin de l'en-tête, en les laissant simplement avec la véritable adresse du client?

Shane Madden
la source
Merci pour la réponse, @Shane. En fait, lorsque vous atteignez nginx, un X-Forwarded-Forexiste déjà. (c’est la bonne adresse IP du client) nginx lui-même ajoute ensuite l’adresse IP de notre équilibreur de charge (le saut précédent) à l’en- X-Forwarded-Fortête. (vraisemblablement en y ajoutant ce qu’il considère comme "adresse distante") Si cela n’était tout simplement pas fait, je pourrais simplement utiliser l’en- X-Forwarded-Fortête comme auparavant. (nous avons récemment migré vers nginx)
Kirk Woll
@Kirk Ainsi, lorsque nginx obtient l'en-tête, il ne s'agit que de l'adresse du client d'origine? Mais quand il le traite, est-il ajouté sur l'en-tête du serveur proxy de connexion? Cela ne tient pas compte - la seule fois où il devrait toucher cet en-tête, c’est lorsqu’il envoie la connexion à un autre proxy via un proxy_pass- et même alors, seulement avec proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;en place.
Shane Madden
Même le W3C se trompe : la documentation indique que "les mandataires doivent ajouter l'adresse IP de l'initiateur de la demande à la fin d'une liste séparée par des virgules dans un champ d'en-tête X-Forwarded-For HTTP", elle doit indiquer le début .
Ian Kemp
3
@IanKemp, non, la fin est correcte. Pour le côté serveur d'un proxy, l' initiateur de la demande (c'est-à-dire une requête TCP ) est le proxy précédent (s'il en existe un). Ce mandataire précédent envoie peut-être déjà un en- X-Forwarded-Fortête avec éventuellement l'adresse du client d'origine à gauche et éventuellement les mandataires précédents ajoutés à celui-ci. Ainsi, le proxy en cours ajoute le proxy précédent (= initiateur) à la fin de la liste et transmet l'en- X-Forwarded-Fortête ainsi augmenté au saut en amont suivant. Certes, ils auraient pu choisir un libellé plus évident.
blubberdiblub
5

X-Real-IP est l'adresse IP du client réel avec lequel le serveur parle (le "vrai" client du serveur), qui, dans le cas d'une connexion mandatée, est le serveur proxy. C'est pourquoi X-Real-IP contiendra la dernière adresse IP dans l'en-tête X-Forwarded-For.

utilisateur558061
la source
1
OK, mais pour moi, ce n’est tout simplement jamais une information utile. Je souhaite obtenir l'adresse IP d'origine du client, ce qui est crucial et, d'après tout ce que j'ai lu, le but de ces en-têtes. Pourquoi voudrais-je connaître l'adresse IP de nos serveurs proxy?
Kirk Woll
Si ce n'est pas utile pour vous, alors ce n'est pas pour vous. Personne ne vous oblige à utiliser X-Real-IP. Si vous avez besoin de l’adresse IP de l’utilisateur dans votre application, demandez à votre application d’analyser X-Forwarded-For (ce qui n’est pas toujours fiable) car certains proxys (appliance de sécurité Internet / pare-feu) ne définissent pas X-Forwarded- Pour). Dans le contexte de nginx, X-Forwarded-For n’est pas important car il n’est de toute façon pas question de communiquer avec ces clients, à part la dernière entrée (X-Real-IP) qui est le client de nginx. Si vous n'en avez pas besoin, ne le définissez pas, ne le désactivez pas ou ignorez-le simplement: /
user558061 le
2
Non, ce que je veux dire est, pourquoi X-Real-IPretournaient l'adresse IP de mon propre serveur proxy jamais être utile?
Kirk Woll
Génial ... répondez mec. Je cherchais cette information précise. J'ai besoin de parler à un serveur ncat sur mon serveur proxy, donc j'ai besoin de cela à la volée.
Yugal Jindle