我在 Heroku 的支持部门工作,并花了一些时间与我们的路由工程师讨论这个问题。我想发布一些额外的信息来澄清一些关于这里发生的事情。
上面答案中提供的示例只是巧合地最后显示了客户端 IP,这并不能真正保证。它不是第一个的原因是因为发起请求声称它正在转发X-Forwarded-For
标头中指定的 IP。当 Heroku 路由器收到请求时,它只是附加了直接连接到X-Forwarded-For
在已注入请求的那一项之后列出。我们的路由器总是将连接到我们平台前面的 AWS ELB 的 IP 添加为列表中的最后一个 IP。这个 IP 可能是原始 IP(在只有一个 IP 的情况下,几乎可以肯定是),但是一旦有多个 IP 链接,所有的赌注都没有了。惯例总是将链中最新的 IP 添加到列表的末尾(这就是我们所做的),但在链上的任何点都可以更改该链并且可以插入不同的 IP。因此,唯一可靠的 IP(从我们平台的角度来看)是列表中的最后一个 IP。
为了说明,假设有人发起一个请求,并在 X-Forwarded-For 标头中任意添加了 3 个额外的 IP:
curl -H "X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4" http://www.google.com
想象这台机器的 IP 是 9.9.9.9,它必须通过一个代理(例如,一所大学的校园代理)。假设代理的 IP 为 2.2.2.2。假设它没有配置为X-Forwarded-For
去除标题(它可能不会),它只会将 9.9.9.9 IP 附加到列表的末尾并将请求传递给 Google。此时,标题将如下所示:
X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9
然后,该请求将通过 Google 的端点,该端点将附加大学代理的 IP 2.2.2.2,因此标题在 Google 的日志中最终将如下所示:
X-Forwarded-For: 12.12.12.12,15.15.15.15,4.4.4.4,9.9.9.9,2.2.2.2
那么,哪个是客户端 IP?从谷歌的角度来看是不可能的。实际上,客户端 IP 是 9.9.9.9。列出的最后一个 IP 是 2.2.2.2,第一个是 12.12.12.12。Google 所知道的是 2.2.2.2 IP 绝对正确,因为那是实际连接到他们服务的 IP——但他们不知道这是否是请求的初始客户端,或者不是来自可用数据。同样,当这个头部只有一个 IP 时——即直接连接到我们服务的 IP,所以我们知道它是可靠的。
从实际的角度来看,这个 IP 在大多数时候很可能是可靠的(因为大多数人不会费心去欺骗他们的 IP)。不幸的是,不可能防止这种欺骗,当请求到达 Heroku 路由器时,我们无法判断X-Forwarded-For
链中的 IP 是否被篡改。
撇开所有可靠性问题不谈,这些 IP 链应始终从左到右读取。客户端 IP应始终是最左边的 IP。