Java面試-如何獲取客戶端真實IP

在進行一些小遊戲開發時,咱們常常比較關注的一個功能即是分享。針對分享,咱們但願能根據各個城市或者地區,能有不一樣的分享文案,辨識地區的功能若是由服務器來完成的話,咱們就須要知道客戶端的真實IP。今天咱們就來看看服務器是如何獲取到客戶端的真實IP的。
<!-- more -->php

nginx配置

首先,一個請求確定是能夠分爲請求頭和請求體的,而咱們客戶端的IP地址信息通常都是存儲在請求頭裏的。若是你的服務器有用Nginx作負載均衡的話,你須要在你的location裏面配置X-Real-IPX-Forwarded-For請求頭:java

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》中,有這麼一句話:linux

通過反向代理後,因爲在客戶端和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裏做一個賦值操做,即我在上面的配置:nginx

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添加配置:web

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。apache

那麼$proxy_add_x_forwarded_for又是什麼?segmentfault

$proxy_add_x_forwarded_for變量包含客戶端請求頭中的X-Forwarded-For$remote_addr兩部分,他們之間用逗號分開。後端

舉個例子,有一個web應用,在它以前經過了兩個nginx轉發,www.linuxidc.com即用戶訪問該web經過兩臺nginx。緩存

在第一臺nginx中,使用:服務器

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,使用:

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

代碼爲:

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插件加上的頭。

HTTP_CLIENT_IP

有些代理服務器會加上此請求頭。在網上搜了一下,有一個說法是:

這是普通的 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 屏蔽代理用戶訪問。

HTTP_X_FORWARDED_FOR

簡稱XFF頭,它表明客戶端,也就是HTTP的請求端真實的IP,只有在經過了HTTP 代理(好比APACHE代理)或者負載均衡服務器時纔會添加該項。它不是RFC中定義的標準請求頭信息,在squid緩存代理服務器開發文檔中能夠找到該項的詳細介紹。若是有該條信息, 說明您使用了代理服務器,地址就是後面的數值。能夠僞造。標準格式以下:X-Forwarded-For: client1, proxy1, proxy2

總結

以上就是我在處理客戶端真實IP的方法,若是你有什麼意見或者建議,能夠在下方留言。

有興趣的話能夠關注個人公衆號或者頭條號,說不定會有意外的驚喜。

相關文章
相關標籤/搜索