Nginx 从下游代理解析用户IP

Nginx 从下游代理解析用户IP,nginx,reverse-proxy,Nginx,Reverse Proxy,我们之前一直在互联网和我们的微服务之间运行一个Nginx反向代理,配置为: proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 请求通过管道传输,标题如下: User -> ALB [nginx] -> App Servers IP: 1.2.3.4 IP: 172.31.1.1

我们之前一直在互联网和我们的微服务之间运行一个Nginx反向代理,配置为:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
请求通过管道传输,标题如下:

User        -> ALB [nginx]            -> App Servers
IP: 1.2.3.4    IP: 172.31.1.1            IP: n/a
               Forwarded-For: 1.2.3.4    Real-IP: 1.2.3.4
                                         Forwarded-For: 1.2.3.4, 172.31.1.1
但是现在我们需要在弹性LB后面扩展ALB,我们发现额外的代理层有问题,例如:

User        -> ELB                    -> ALB [nginx]                        -> App Servers
IP: 1.2.3.4    IP: 172.31.1.2            IP: 172.31.1.1                        IP: n/a
               Forwarded-For: 1.2.3.4    Forwarded-For: 1.2.3.4, 172.31.1.2    Real-IP: 172.31.1.2
                                                                               Forwarded-For: 1.2.3.4, 172.31.1.2
但正如您所看到的,这目前只是将
X-Real-IP:
设置为ELB的IP

我们需要能够剥离受信任的代理,并在
X-Real-IP
头中发送适当的用户IP,以及记录用户IP而不是ELB IP

GeoIP模块有
GeoIP\u proxy
指令,这些指令定义了在确定“真实”IP时要忽略的可信代理,我想知道nginx中是否有类似的东西或其他方法来实现这一点


TIA

简单的回答是,没有一个简单的配置指令,也没有一个100%可靠的方法来只信任某些代理

让我们构造一个示例。我的IP是
1.2.3.4
,但我是恶意的,我想假装我是
5.6.7.8
。我通过浏览器扩展插入自己的X-Forwarded-For:header,nginx框得到:

X-Forwarded-For: 5.6.7.8, 1.2.3.4, 172.31.1.1, 172.31.1.2
1.简单但有缺陷 所有这一切只需剥离
X-Forwarded-for:
头的第一个IP地址,如果您不介意用户通过头注入欺骗其他IP地址,那么这一切都很好。在上述示例中,此方法将返回伪造的
5.6.7.8

2.有点复杂,但大多数情况下都可以接受 理想情况下,我们只想剥离两个受信任的代理并使用第一个未经授权的IP。为此,我们必须对正则表达式进行一些创新:

map $proxy_add_x_forwarded_for $x_real_ip {
  "~(?:^|, )([^,]+), (?:10\.|172\.(?:1[6-9]|2[0-9]|3[01])\.).*" $1;
  default $remote_addr;
}
大约一半的正则表达式只是处理172.16.0.0/12网络没有在八位组边界上完全分裂的事实,但它确实做到了这一点。对于上述示例,它正确返回
1.2.3.4

但是,如果外部攻击者不知何故知道此kludgey配置正在使用,并且还知道受信任的网络是什么,则他们可以设置以下标头来绕过它:

X-Forwarded-For: 5.6.7.8, 172.16.0.1
最终在代理服务器上显示为:

X-Forwarded-For: 5.6.7.8, 172.16.0.1, 1.2.3.4, 172.31.1.1, 172.31.1.2
由于该正则表达式基本上是从左向右读取,并将IP返回到第一个受信任IP的左侧,因此在这种特定情况下,它将返回伪造的
5.6.7.8
IP。然而,这是一个非常棘手的问题,对于我的特殊用途YMMV来说是可以接受的

警告:您可能会收到一个错误,提示“您应该增加map\u hash\u bucket\u size”,这意味着您需要增加该值以适应bigass regex。但是,您可能会有点烦躁,并且谈论“对齐”很重要,因此如果您没有在其他地方设置该值,我建议将消息中引用的值加倍。就我而言,我把它从64倍增加到了128倍

3.一个真正合适的、防弹的解决方案 IMHO这需要实际解析报头并应用实际逻辑,因此需要将其修补到nginx或写入模块中。基本上移植了GeoIP模块用于
GeoIP\u proxy
GeoIP\u proxy\u recursive
的相同逻辑

或者,您可以让您的应用程序代理感知并在那里实现逻辑。如果你知道如何正确地解决IP和子网之间的矛盾,那就轻而易举了。不幸的是,在这种情况下,我没有这个选择


谢谢:如果不是IRC上的membear提醒我,regex捕获组在
map{}
块中是有效的,我可能仍然在旋转轮子


无耻的插件:在我记得我问过这里之前,我最初写过这篇文章。基本相同,但也有一个更详细的大正则表达式细分。

你的问题在StackOverflow中是离题的。如果您将其移动到或,您将有更好的机会得到答复。
X-Forwarded-For: 5.6.7.8, 172.16.0.1, 1.2.3.4, 172.31.1.1, 172.31.1.2