阻止 Elastic Load Balancer 泄露内部私有 IP

Stop Elastic Load Balancer From Revealing Internal Private IP

我注意到,ELB 后面的 ec2 实例的内部 IP,即使在私有子网中,也会在发出特定类型的请求时显示。特别是 HOST 值为空的那个。

telnet site_url 80
GET / HTTP/1.0

返回的 headers:

HTTP/1.1 301 Moved Permanently
Cache-Control: max-age=1209600
Content-Type: text/html; charset=iso-8859-1
Date: Thu, 26 Mar 2015 18:47:22 GMT
Expires: Thu, 09 Apr 2015 18:47:22 GMT
Location: https://10.0.7.35/
Server: Apache
Content-Length: 226
Connection: Close

当然这也会发生在 443 上的开放 ssl 请求。

有人知道这个问题的解决方案或解决方案吗?我知道 IIS 也有同样的症状,但我的问题是 AWS ELB 特有的。

编辑:

Apache 重定向以强制使用 HTTPS。

RewriteCond %{HTTPS} off
RewriteCond %{SERVER_ADDR} !^127\.0\.0\.1
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

这真的与 ELB 无关,而与 Apache 无关,这显然是返回此信息的原因(因此输出中的 server: Apache 行)。

你显然在你的 Apache 配置中定义了某种重定向来将流量从端口 80 重定向到端口 443。你应该更新你的问题以包括你的 Apache 配置文件的相关部分,包括任何重写规则、服务器名称、.htaccess 设置等

编辑:

您在重写规则中使用了 HTTP_HOST,它对应于请求中提供的主机。在您提供的示例中,您没有提供主机,因此请尝试这样做:

$ telnet www.example.com 80
GET / HTTP/1.0
Host: www.example.com

如果定义了虚拟主机,则请求的主机部分是必需的,这样 Apache 就知道应该将请求路由到哪个虚拟主机。

您可能还想按照这些行添加另一个重写条件:

RewriteCond %{HTTP_HOST} !^www.example.com
RewriteRule ^(.*)$ https://www.example.com [R=301,L]

这将确保如果有人在没有提供包含 header 的完整请求的情况下尝试访问您的站点,它将重定向到正确的域。

我们最近几天一直在研究这个问题并得出结论:

  1. 当 ELB 看到一个没有主机的请求时 header,它一定是决定(真诚地)代表您添加一个主机,并使用自己的私有 IP 地址作为其值。
  2. 这向 Apache 提供了一个(更多)有效请求,因此它生成的任何重定向都使用未修改的 HTTP_HOST 值。

我们确实找到了适合我们的解决方案(虽然我们只需要在我们的 "default" VirtualHost 中解决这个问题),您可能会考虑将其添加到您的 VirtualHost:

UseCanonicalName On

在我们的评估中,这指示某些 Apache 行为正式替换响应中的 HTTP_HOST ServerName 指令,这解决了我们试图解决的问题。

通过将我们 Public VPC 子网上的 IP 主机字段重写为我们的主域名来解决 Varnish Cache 中的这个问题。

    if(req.http.host ~ "10.30.0") {
     set req.http.host = "www.mydomain.com";
    }

一个朋友 post 今天编辑了这个,尽管已经有了答案,但我想我应该把我发现的细节写进去。

使用原始 post 中描述的机制,我能够重现所描述的场景,其中返回的 Location header 确实是一个 https:// 地址。

然而,经过更仔细的检查,提供的地址 不是 我的任何实例地址 - 而它似乎是来自 ELB 实例本身的 IP 地址.

我通过检查 ELB 后面的一个实例进一步证实了这一点,并使用这样的命令序列,我能够确认 GET / 命令返回的 IP 地址确实是 ELB 的.

# These commands are purely to assist in obscuring my own IPs. :)
$ export LOCALIP=$(ifconfig  | grep 'inet addr:'| grep -v '127.0.0.1' | cut -d: -f2 | awk '{ print }')
$ export DISCOVEREDIP=<the IP from the GET test>

# I'm also using `sed` here to replace real IPs with strings to demonstrate which node is which
$ ss -tn | grep $DISCOVEREDIP | sed -e "s/$LOCALIP/localip/" -e "s/$DISCOVEREDIP/discoveredip/" | head -n 3
ESTAB      0      0            localip:80           discoveredip:3950
ESTAB      0      0            localip:80           discoveredip:4157
ESTAB      0      0            localip:80           discoveredip:4148

所以我可以得出我的网络服务器的本地 IP 地址正在侦听 ELB 指向的端口 80,并且 ELB 的 IP 使用更高的端口连接到我的网络服务器。

没有超出 ELB 内部 IP 地址的暴露,无需担心。云彩快乐!