Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.1k views
in Technique[技术] by (71.8m points)

http - Get client's real IP address on Heroku

On Heroku Cedar, I wanted to get the client's IP. First attempt:

ENV['REMOTE_ADDR']

This does not work, of course, because all requests are passed through proxies. So the alternative was to use:

ENV['HTTP_X_FORWARDED_FOR']

But this is not quite safe, is it?

If it contains only one value, I take this. If it contains more than one value (comma-separated), I could take the first one.

But what if someone manipulates this value? I cannot trust ENV['HTTP_X_FORWARDED_FOR'] as I could with ENV['REMOTE_ADDR']. And there is no list of trusted proxies that I could use, either.

But there must be some way to reliably get the client's IP address, always. Do you know one?

In their docs, Heroku describes that X-Forwarded-For is "the originating IP address of the client connecting to the Heroku router".

This sounds as if Heroku could be overwriting the X-Forwarded-For with the originating remote IP. This would prevent spoofing, right? Can someone verify this?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

From Jacob, Heroku's Director of Security at the time:

The router doesn't overwrite X-Forwarded-For, but it does guarantee that the real origin will always be the last item in the list.

This means that, if you access a Heroku app in the normal way, you will just see your IP address in the X-Forwarded-For header:

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

If you try to spoof the IP, your alleged origin is reflected, but - critically - so is your real IP. Obviously, this is all we need, so there's a clear and secure solution for getting the client's IP address on Heroku:

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

This is just the opposite of what is described on Wikipedia, by the way.

PHP implementation:

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'];
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...