web-dev-qa-db-fra.com

nginx real_ip_header et X-Forwarded-For semble faux

La description wikipedia de l'en-tête HTTP X-Forwarded-For est:

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

La documentation nginx pour la directive real_ip_header lit en partie:

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 le last ip dans l'en-tête X-Forwarded-For pour le remplacement. [Je souligne]

Ces deux descriptions semblent en contradiction. Dans notre scénario, le X-Forwarded-For l'en-tête est exactement comme décrit - l'adresse IP "réelle" du client est l'entrée la plus à gauche. De même, le comportement de nginx consiste à utiliser le droit - la plus grande valeur - qui, évidemment, n'est qu'un de nos serveurs proxy.

Ma compréhension de X-Real-IP est qu'il est supposé être utilisé pour déterminer le réel adresse IP du client - pas le proxy. Suis-je en train de manquer quelque chose, ou est-ce un bogue dans nginx?

Et, au-delà de cela, quelqu'un a-t-il des suggestions sur la façon de faire le X-Real-IP l'en-tête affiche la valeur gauche - la plus élevée, comme indiqué par la définition de X-Forwarded-For?

62
Kirk Woll

Je crois que la clé pour résoudre les problèmes liés à X-Forwarded-For lorsque plusieurs adresses IP sont chaînées est l'option de configuration récemment introduite, real_ip_recursive (ajouté dans nginx 1.2.1 et 1.3.0). À partir des nginx realip docs :

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

nginx récupérait la dernière adresse IP de la chaîne par défaut car c'était la seule qui était supposée être de confiance. Mais avec le nouveau real_ip_recursive activé et avec plusieurs set_real_ip_from options, vous pouvez définir plusieurs proxies approuvés et il récupérera la dernière IP non approuvée.

Par exemple, avec cette configuration:

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 résultant en:

X-Forwarded-For: 123.123.123.123, 192.168.2.1, 127.0.0.1

nginx va maintenant choisir 123.123.123.123 comme adresse IP du client.

Quant à savoir pourquoi nginx ne se contente pas de choisir l'adresse IP la plus à gauche et vous oblige à définir explicitement des proxies de confiance, c'est pour empêcher une usurpation d'adresse IP facile.

Supposons que la véritable adresse IP d'un client soit 123.123.123.123. Supposons également que le client ne fonctionne pas bien et qu'il essaie d'usurper son adresse IP pour qu'il soit 11.11.11.11. Ils envoient une requête au serveur avec cet en-tête déjà en place:

X-Forwarded-For: 11.11.11.11

Étant donné que les procurations inverses ajoutent simplement des adresses IP à cette chaîne X-Forwarded-For, disons qu'elle finit par ressembler à ceci lorsque nginx y arrive:

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, cela permettrait au client d'usurper facilement son adresse IP. Mais avec l'exemple de configuration nginx ci-dessus, nginx ne fera confiance qu'aux deux dernières adresses en tant que proxys. Cela signifie que nginx choisira correctement 123.123.123.123 comme adresse IP, bien que cette IP usurpée soit en fait la plus à gauche.

105
Nick M

L'analyse du X-Forwarded-For l'en-tête est en effet défectueux 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 arrête de chercher et colle la partie à droite de l'espace ou de la virgule dans la variable IP. Il s'agit donc de l'adresse proxy la plus récente en tant qu'adresse client originale .

Il ne joue pas à Nice selon les spécifications; c'est le danger de ne pas l'avoir énoncé en termes douloureusement évidents dans un RFC.

Mis à part: Il est même difficile de trouver une bonne source primaire sur le format, qui a été initialement défini par Squid - un Dig à travers leur documentation confirme la commande; le plus à gauche est le client d'origine, le plus à droite est le plus récent ajout. Je suis vraiment tenté d'ajouter un [citation nécessaire] à cette page wikipedia. Un modification anonyme semble être l'autorité d'Internet sur le sujet.

Si possible, pouvez-vous demander à vos mandataires intermédiaires de cesser de s'ajouter à la fin de l'en-tête, en le laissant uniquement avec la véritable adresse client?

9
Shane Madden

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

5
user558061

Plus un avertissement qu'une réponse ...

J'ai essayé d'ajouter des serveurs de cache Nginx dans plusieurs emplacements de carte sans réaliser que mon serveur principal (source de données) est déjà derrière un serveur de cache Nginx qui s'exécute localement, parfois le serveur local est configuré pour exécuter Apache et Nginx est placé devant pour servir de cache.

L'ajout d'un deuxième serveur de cache Nginx séparé entraînerait deux serveurs de cache et donc votre HTTP_X_REAL_IP ou HTTP_X_FORWARDED_FOR semble incorrect, montrant l'ip d'un si les serveurs au lieu de l'IP du visiteur.

Dans mon cas, j'ai corrigé cela en définissant le nouveau serveur de cache prendre des données directement à partir du port Apache (port 7080 dans mon cas) en contournant le cache Nginx local sur le serveur source/principal.

Une autre solution serait de supprimer le HTTP_X_REAL_IP sur le serveur de cache local.

J'exécutais Plesk panel btw.

0
adrianTNT