在Heroku Cedar上,我想获取客户端的IP地址。第一次尝试:
ENV['REMOTE_ADDR']
当然,这是行不通的,因为所有请求都是通过代理传递的。因此,另一种选择是使用:
ENV['HTTP_X_FORWARDED_FOR']
但这不太安全,不是吗?
如果它只包含一个值,我接受这个。如果它包含多个值(逗号分隔),我可以采用第一个值。
但是如果有人操纵了这个值呢?我不能像对ENV['REMOTE_ADDR']
那样信任ENV['HTTP_X_FORWARDED_FOR']
。而且我也没有可以使用的可信代理的列表。
但是,必须有某种方法来可靠地获取客户端的IP地址。你认识一个吗?
在their docs中,Heroku描述了X-Forwarded-For
是“连接到Heroku路由器的客户端的原始IP地址”。
这听起来好像Heroku可以用原始的远程IP覆盖X-Forwarded-For
。这可以防止欺骗,对吧?有人能证实这一点吗?
发布于 2016-05-06 06:42:03
我在Heroku的支持部门工作,花了一些时间和我们的路由工程师讨论这个问题。我想发布一些额外的信息,以澄清这里发生的一些事情。
上面答案中提供的示例只是巧合地最后显示了客户端IP,这并不是真正有保证的。它不是第一个的原因是因为原始请求声称它转发的是X-Forwarded-For
标头中指定的IP。当Heroku路由器收到请求时,它只是将直接连接到X-Forwarded-For
列表的IP添加到已注入到请求中的IP之后。我们的路由器始终将连接到我们平台前面的AWS ELB的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添加到列表的末尾,并将请求传递给谷歌。此时,标头将如下所示:
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
链中的in是否被篡改了。
除了可靠性问题之外,这些IP链应该始终从左到右读取。客户端IP应该始终是最左边的IP。
发布于 2013-08-16 09:45:21
您永远不能真正信任来自客户端的任何信息。这更多的是一个你信任谁以及如何验证的问题。即使是Heroku也可能会受到影响,如果他们的代码中有一个bug,或者他们被黑客攻击了,那么他们可能会提供一个糟糕的HTTP_X_FORWARDED_FOR
值。另一种选择是一些其他的Heroku机器在内部连接到你的服务器,并完全绕过他们的代理,同时伪造REMOTE_ADDR
和/或HTTP_X_FORWARDED_FOR
。
这里最好的答案取决于你想要做什么。如果您正在尝试验证客户端,客户端证书可能是更合适的解决方案。如果您只需要地理位置的IP,那么信任输入可能就足够了。最坏的情况是,有人会伪造位置并得到错误的内容...如果您有不同的用例,在这两个极端之间还有许多其他的解决方案。
https://stackoverflow.com/questions/18264304
复制相似问题