标签归档:X-Real-IP

绕过代理服务器获取客户端IP

一般来说,Web应用和客户端之间隔着很多个代理服务器,无论正向代理还是反向代理。这样就给本地资讯类应用(新闻、天气等)或者统计(审计,追踪等)需求带来了麻烦,因为在应用通过request.getRemoteAddr()方法(以Java为例)往往只能拿到与自己直接通信的设备IP。因此,如果用户通过直接或者间接的正向代理(ISP提供的缓存服务器等)上网,Web应用只会取到正向代理服务器地址;如果Web应用前端部署着Nginx或者Apache之类的反向代理,Web应用只会取到反向代理的地址。

面对这样的限制,代理厂商利用HTTP自定义Header规避了问题。比如Nginx,可以添加以下配置:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

它向后端应用传递了两个HTTP自定义Header,X-Real-IP和X-Forwarded-For。这两个Header作用类似,都是向后端透传客户端源IP,但是又有一些不同,主要区别在于:

1. X-Forwarded-For已有标准RFC文档(RFC 7239)定义,而X-Real-IP没有。
2. X-Forwarded-For Header格式为X-Forwarded-For: client1, proxy1, proxy2,每级代理都会将与自己直接通信的对端IP追加在X-Forwarded-For中,因此应用还需要额外解析IP列表以获取所需IP。而X-Real-IP只会记录与自己直接通信的对端IP。

由此,反向代理后面的应用服务器可以通过X-Real-IP或者X-Forwarded-For请求头来获取客户端IP:

String xRealIp = request.getHeader("X-Real-IP");
String xForwardIps = request.getHeader("X-Forwarded-For");

另外需要注意的是,HTTP Header是很容易被伪造的,因此,X-Forwarded-For Header中的首个IP也不意味着就一定是客户端源IP。从安全性方面来说,如果应用前不加反向代理,则request.getRemoteAddr()拿到的IP便是可信的,无法伪造;如果加了反向代理,那么X-Real-IP和X-Forwarded-For IP的最后一个IP是可信的,无法伪造。

--EOF--