caw*_*caw 31 http ip-address heroku
在Heroku Cedar上,我想获得客户端的IP.第一次尝试:
ENV['REMOTE_ADDR']
Run Code Online (Sandbox Code Playgroud)
当然,这不起作用,因为所有请求都通过代理传递.所以替代方案是使用:
ENV['HTTP_X_FORWARDED_FOR']
Run Code Online (Sandbox Code Playgroud)
但这不太安全,是吗?
如果它只包含一个值,我就拿这个.如果它包含多个值(以逗号分隔),我可以选择第一个值.
但是,如果有人操纵这个价值呢?我不能相信ENV['HTTP_X_FORWARDED_FOR'],我可以用ENV['REMOTE_ADDR'].并且我也没有可以使用的可信代理列表.
但总是必须有一些方法来可靠地获取客户端的IP地址.你知道吗?
在他们的文档中,Heroku描述了X-Forwarded-For"连接到Heroku路由器的客户端的原始IP地址".
听起来好像Heroku可能会X-Forwarded-For用原始的远程IP 覆盖它.这样可以防止欺骗,对吧?有人可以验证吗?
caw*_*caw 40
来自Heroku当时的安全总监雅各布:
路由器不会覆盖
X-Forwarded-For,但它确保真正的原点始终是列表中的最后一项.
这意味着,如果您以正常方式访问Heroku应用程序,您将只在X-Forwarded-For标题中看到您的IP地址:
$ curl http://httpbin.org/ip
{
"origin": "123.124.125.126",
}
Run Code Online (Sandbox Code Playgroud)
如果你试图欺骗知识产权,你的所谓来源就会被反映出来,但是 - 关键 - 你的真实IP也是如此.显然,这就是我们所需要的,因此有一个清晰安全的解决方案可以在Heroku上获取客户端的IP地址:
$ curl -H"X-Forwarded-For: 8.8.8.8" http://httpbin.org/ip
{
"origin": "8.8.8.8, 123.124.125.126"
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,这与维基百科上描述的情况正好相反.
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'];
}
}
Run Code Online (Sandbox Code Playgroud)
Joe*_*son 27
我在Heroku的支持部门工作,并花了一些时间与我们的路由工程师讨论这个问题.我想发布一些额外的信息来澄清一些关于这里发生了什么的事情.
上面答案中提供的示例只是巧妙地显示了客户端IP,并且不能保证.它不是第一个的原因是因为原始请求声称它正在转发X-Forwarded-For标头中指定的IP .当Heroku路由器收到请求时,它只是X-Forwarded-For在注入请求之后附加了直接连接到列表的IP .我们的路由器始终将连接到我们平台前面的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
Run Code Online (Sandbox Code Playgroud)
想象一下,这台机器的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
Run Code Online (Sandbox Code Playgroud)
然后该请求将通过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
Run Code Online (Sandbox Code Playgroud)
那么,哪个是客户端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.