前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java服务器获取客户端的真实IP

Java服务器获取客户端的真实IP

作者头像
健程之道
发布2019-11-03 13:02:43
4.7K0
发布2019-11-03 13:02:43
举报
文章被收录于专栏:健程之道健程之道

在进行一些小游戏开发时,我们比较关注的一个功能便是分享。我们希望能根据各个城市或者地区,能有不同的分享文案,辨识地区的功能如果由服务器来完成的话,我们就需要知道客户端的真实IP。今天我们就来看看服务器是如何获取到客户端的真实IP的。

nginx配置

首先,一个请求肯定是可以分为请求头和请求体的,而我们客户端的IP地址信息一般都是存储在请求头里的。如果你的服务器有用Nginx做负载均衡的话,你需要在你的location里面配置 X-Real-IPX-Forwarded-For请求头:

代码语言:javascript
复制
location ^~ /your-service/ {
                proxy_set_header        X-Real-IP       $remote_addr;
                proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass http://localhost:60000/your-service/;
        }

X-Real-IP

在《实战nginx》中,有这么一句话:

代码语言:javascript
复制
经过反向代理后,由于在客户端和web服务器之间增加了中间层,因此web服务器无法直接拿到客户端的ip,通过$remote_addr变量拿到的将是反向代理服务器的ip地址。

这句话的意思是说,当你使用了nginx反向服务器后,在web端使用 request.getRemoteAddr()(本质上就是获取 $remote_addr),取得的是nginx的地址,即 $remote_addr变量中封装的是nginx的地址,当然是没法获得用户的真实ip的。但是,nginx是可以获得用户的真实ip的,也就是说nginx使用 $remote_addr变量时获得的是用户的真实ip,如果我们想要在web端获得用户的真实ip,就必须在nginx里作一个赋值操作,即我在上面的配置:

代码语言:javascript
复制
proxy_set_header        X-Real-IP       $remote_addr;

X-Forwarded-For

X-Forwarded-For变量,这是一个squid开发的,用于识别通过HTTP代理或负载平衡器原始IP一个连接到Web服务器的客户机地址的非rfc标准,如果有做 X-Forwarded-For设置的话,每次经过proxy转发都会有记录,格式就是 client1,proxy1,proxy2以逗号隔开各个地址,由于它是非rfc标准,所以默认是没有的,需要强制添加。在默认情况下经过proxy转发的请求,在后端看来远程地址都是proxy端的ip 。也就是说在默认情况下我们使用 request.getAttribute("X-Forwarded-For")获取不到用户的ip,如果我们想要通过这个变量获得用户的ip,我们需要自己在nginx添加配置:

代码语言:javascript
复制
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;

意思是增加一个 $proxy_add_x_forwarded_forX-Forwarded-For里去,注意是增加,而不是覆盖,当然由于默认的 X-Forwarded-For值是空的,所以我们总感觉 X-Forwarded-For的值就等于 $proxy_add_x_forwarded_for的值,实际上当你搭建两台nginx在不同的ip上,并且都使用了这段配置,那你会发现在web服务器端通过 request.getAttribute("X-Forwarded-For")获得的将会是客户端ip和第一台nginx的ip。

那么 $proxy_add_x_forwarded_for又是什么?

$proxy_add_x_forwarded_for变量包含客户端请求头中的 X-Forwarded-For$remote_addr两部分,他们之间用逗号分开。

举个例子,有一个web应用,在它之前通过了两个nginx转发, www.linuxidc.com即用户访问该web通过两台nginx。

在第一台nginx中,使用:

代码语言:javascript
复制
proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

现在的 $proxy_add_x_forwarded_for变量的 X-Forwarded-For部分是空的,所以只有 $remote_addr,而 $remote_addr的值是用户的ip,于是赋值以后, X-Forwarded-For变量的值就是用户的真实的ip地址了。

到了第二台nginx,使用:

代码语言:javascript
复制
proxy_set_header            X-Forwarded-For $proxy_add_x_forwarded_for;

现在的 $proxy_add_x_forwarded_for变量, X-Forwarded-For部分包含的是用户的真实ip, $remote_addr部分的值是上一台nginx的ip地址,于是通过这个赋值以后现在的 X-Forwarded-For的值就变成了“用户的真实ip,第一台nginx的ip”,这样就清楚了吧。

服务器获取真实IP

代码为:

代码语言:javascript
复制
public static String getIpAddress(HttpServletRequest request) {
    String Xip = request.getHeader("X-Real-IP");
    String XFor = request.getHeader("X-Forwarded-For");

    if (!Strings.isNullOrEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
      //多次反向代理后会有多个ip值,第一个ip才是真实ip
      int index = XFor.indexOf(",");
      if (index != -1) {
        return XFor.substring(0, index);
      } else {
        return XFor;
      }
    }
    XFor = Xip;
    if (!Strings.isNullOrEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
      return XFor;
    }
    if (Strings.nullToEmpty(XFor).trim().isEmpty() || "unknown".equalsIgnoreCase(XFor)) {
      XFor = request.getHeader("Proxy-Client-IP");
    }
    if (Strings.nullToEmpty(XFor).trim().isEmpty() || "unknown".equalsIgnoreCase(XFor)) {
      XFor = request.getHeader("WL-Proxy-Client-IP");
    }
    if (Strings.nullToEmpty(XFor).trim().isEmpty() || "unknown".equalsIgnoreCase(XFor)) {
      XFor = request.getHeader("HTTP_CLIENT_IP");
    }
    if (Strings.nullToEmpty(XFor).trim().isEmpty() || "unknown".equalsIgnoreCase(XFor)) {
      XFor = request.getHeader("HTTP_X_FORWARDED_FOR");
    }
    if (Strings.nullToEmpty(XFor).trim().isEmpty() || "unknown".equalsIgnoreCase(XFor)) {
      XFor = request.getRemoteAddr();
    }
    return XFor;
  }

我们来看看各个请求头的含义

X-Real-IP

nginx代理一般会加上此请求头。

X-FORWARDED-FOR

这是一个 Squid开发的字段,只有在通过了HTTP代理或者负载均衡服务器时才会添加该项。

Proxy-Client-IP 和 WL-Proxy-Client-IP

这个一般是经过apache http服务器的请求才会有,用apache http做代理时一般会加上 Proxy-Client-IP请求头,而 WL-Proxy-Client-IP是它的weblogic插件加上的头。

HTTPCLIENTIP

有些代理服务器会加上此请求头。在网上搜了一下,有一个说法是:

代码语言:javascript
复制
这是普通的 http header,伪造起来很容易,不要轻易信任用户输入。 

curl -H 'client-ip: 8.8.8.8' lidian.club/phpinfo.php | grep _SERVER 
你就能看到 _SERVER["HTTP_CLIENT_IP"] 了。 

client-ip 和 client-host 是在 NAPT 还没普及的年代,企业内网假设的 http 透明代理,传给服务器的 header,只有极少数厂家用过,从来不是标准,也从来没成为过事实标准。 
(大家最熟悉的事实标准就是 x-forwarded-for) 

后来出现的 web proxy 也没见用过这个 header。 

TCP/IP Illustrated Vol 3 没有讲过这个 header,网上的传言不可信。 
可考的最早痕迹出现在2005年,日本一部 Perl/CGI 秘籍(9784798010779,270页)通过 client-ip 与 via 两个 header 屏蔽代理用户访问。

HTTPXFORWARDED_FOR

简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,只有在通过了HTTP 代理(比如APACHE代理)或者负载均衡服务器时才会添加该项。它不是RFC中定义的标准请求头信息,在squid缓存代理服务器开发文档中可以找到该项的详细介绍。如果有该条信息, 说明您使用了代理服务器,地址就是后面的数值。可以伪造。标准格式如下:X-Forwarded-For: client1, proxy1, proxy2

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-02-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 健程之道 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • nginx配置
    • X-Real-IP
      • X-Forwarded-For
      • 服务器获取真实IP
        • X-Real-IP
          • X-FORWARDED-FOR
            • Proxy-Client-IP 和 WL-Proxy-Client-IP
              • HTTPCLIENTIP
                • HTTPXFORWARDED_FOR
                相关产品与服务
                负载均衡
                负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档