web-dev-qa-db-fra.com

Obtenez la véritable adresse IP du client sur Heroku

Sur Heroku Cedar, je voulais obtenir l'IP du client. Premier essai:

ENV['REMOTE_ADDR']

Cela ne fonctionne pas, bien sûr, car toutes les demandes sont transmises via des proxys. Donc, l'alternative était d'utiliser:

ENV['HTTP_X_FORWARDED_FOR']

Mais ce n'est pas tout à fait sûr, n'est-ce pas?

S'il ne contient qu'une seule valeur, je prends ceci. S'il contient plus d'une valeur (séparée par des virgules), je pourrais prendre la première.

Mais que faire si quelqu'un manipule cette valeur? Je ne peux pas faire confiance ENV['HTTP_X_FORWARDED_FOR'] comme je pouvais avec ENV['REMOTE_ADDR']. Et il n'y a pas non plus de liste de proxys de confiance que je pourrais utiliser.

Mais il doit y avoir un moyen pour obtenir de manière fiable l'adresse IP du client, toujours. En connaissez-vous un?

Dans leurs documents , Heroku décrit que X-Forwarded-For est "l'adresse IP d'origine du client se connectant au routeur Heroku".

Cela semble comme si Heroku pouvait écraser le X-Forwarded-For avec l'adresse IP distante d'origine. Cela empêcherait l'usurpation d'identité, non? Quelqu'un peut-il vérifier cela?

34
caw

De Jacob, directeur de la sécurité d'Heroku à l'époque:

Le routeur n'écrase pas X-Forwarded-For, mais cela garantit que la véritable origine sera toujours l'élément dernier dans la liste.

Cela signifie que, si vous accédez normalement à une application Heroku, vous verrez simplement votre adresse IP dans le X-Forwarded-For entête:

$ curl http://httpbin.org/ip
{
  "Origin": "123.124.125.126",
}

Si vous essayez d'usurper l'IP, votre origine présumée est reflétée, mais - de manière critique - votre IP réelle l'est également. Évidemment, c'est tout ce dont nous avons besoin, il existe donc une solution claire et sécurisée pour obtenir l'adresse IP du client sur Heroku:

$ curl -H"X-Forwarded-For: 8.8.8.8" http://httpbin.org/ip
{
  "Origin": "8.8.8.8, 123.124.125.126"
}

C'est juste l'opposé de ce qui est décrit sur Wikipedia , soit dit en passant.

Implémentation PHP:

function getIpAddress() {
    if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $ipAddresses = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim(end($ipAddresses));
    }
    else {
        return $_SERVER['REMOTE_ADDR'];
    }
}
45
caw

Je travaille dans le service d'assistance de Heroku et j'en ai discuté avec nos ingénieurs de routage. Je voulais publier des informations supplémentaires pour clarifier certaines choses sur ce qui se passe ici.

Dans l'exemple fourni dans la réponse ci-dessus, l'adresse IP du client était affichée en dernier par coïncidence et ce n'est pas vraiment garanti. La raison pour laquelle ce n'était pas le premier est que la demande d'origine a prétendu qu'elle transmettait pour l'IP spécifiée dans le X-Forwarded-For entête. Lorsque le routeur Heroku a reçu la demande, il a simplement ajouté l'adresse IP qui se connectait directement au X-Forwarded-For liste après celle qui avait été injectée dans la requête. Notre routeur ajoute toujours l'IP qui s'est connectée à l'AWS ELB en face de notre plate-forme en tant que dernière IP de la liste. Cette IP pourrait être celle d'origine (et dans le cas où il n'y a qu'une seule IP, elle l'est presque certainement), mais à l'instant où plusieurs IP sont enchaînées, tous les paris sont désactivés. La convention consiste toujours à ajouter la dernière IP de la chaîne à la fin de la liste (ce que nous faisons), mais à tout moment de la chaîne, cette chaîne peut être modifiée et différentes IP peuvent être insérées. En tant que tel, la seule IP fiable (du point de vue de notre plate-forme) est la dernière IP de la liste.

Pour illustrer cela, supposons que quelqu'un lance une demande et ajoute arbitrairement 3 adresses IP supplémentaires à l'en-tête X-Forwarded-For:

curl -H "X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4" http://www.google.com

Imaginez que l'IP de cette machine était 9.9.9.9 et qu'elle devait passer par un proxy (par exemple, un proxy à l'échelle du campus d'une université). Disons que le proxy avait une IP de 2.2.2.2. En supposant qu'il n'a pas été configuré pour supprimer X-Forwarded-For en-têtes (ce qui ne serait probablement pas le cas), il collerait simplement l'IP 9.9.9.9 à la fin de la liste et transmettrait la demande à Google. À ce stade, l'en-tête ressemblerait à ceci:

X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9

Cette demande passera ensuite par le point de terminaison de Google, qui ajoutera l'IP du proxy universitaire 2.2.2.2, de sorte que l'en-tête ressemblera finalement à ceci dans les journaux de Google:

X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9,2.2.2.2

Alors, quelle est l'IP du client? Il est impossible de dire du point de vue de Google. En réalité, l'adresse IP du client est 9.9.9.9. La dernière IP répertoriée est cependant 2.2.2.2 et la première est 12.12.12.12. Tout ce que Google sait, c'est que l'IP 2.2.2.2 est définitivement correcte car c'est l'IP qui s'est réellement connectée à leur service - mais ils ne sauraient pas si c'était le client initial de la demande ou non à partir des données disponibles. De la même manière, lorsqu'il n'y a qu'une seule IP dans cet en-tête - c'est l'IP qui se connecte directement à notre service, nous savons donc que c'est fiable.

D'un point de vue pratique, cette adresse IP sera probablement fiable la plupart du temps (car la plupart des gens ne prendront pas la peine d'usurper leur adresse IP). Malheureusement, il est impossible d'empêcher ce type d'usurpation d'identité et au moment où une demande parvient au routeur Heroku, il nous est impossible de dire si les adresses IP dans un X-Forwarded-For la chaîne a été falsifiée ou non.

Tous les problèmes de fiabilité mis à part, ces chaînes IP doivent toujours être lues de gauche à droite. L'IP client devrait toujours être l'IP la plus à gauche.

28
Joel Watson

Vous ne pouvez jamais vraiment faire confiance aux informations provenant du client. Il s'agit plutôt de savoir en qui vous avez confiance et comment le vérifier. Même Heroku peut éventuellement être influencé pour fournir un mauvais HTTP_X_FORWARDED_FOR valeur s'ils ont un bogue dans leur code, ou s'ils sont piratés d'une manière ou d'une autre. Une autre option serait une autre machine Heroku se connectant à votre serveur en interne et contournant leur proxy tout en simulant REMOTE_ADDR et/ou HTTP_X_FORWARDED_FOR.

La meilleure réponse ici dépend de ce que vous essayez de faire. Si vous essayez de vérifier vos clients, un certificat côté client peut être une solution plus appropriée. Si vous n'avez besoin que de l'IP pour la géolocalisation, faire confiance à l'entrée peut être suffisant. Le pire des cas, quelqu'un va truquer l'emplacement et obtenir le mauvais contenu ... Si vous avez un cas d'utilisation différent, il existe de nombreuses autres solutions entre ces deux extrêmes.

3
kichik