2013-02-27 52 views
16

我們在ELB後面的EC2上有一些PHP服務器。我們想通過連接到我們的服務器的客戶端的IP地址來確定區域/區域。問題是PHP服務器只能看到ELB的IP地址。我們希望看到通過ELB的客戶端的IP地址。確定客戶端在Amazon ELB後面的IP地址

回答

20

按照AWS docs,該ELB應設置「X - 轉發,對於」 HTTP標頭,保留了原有的客戶端IP地址:

的X轉發,對於請求頭可幫助您識別客戶端的IP地址。由於負載均衡器攔截客戶端和服務器之間的流量,因此您的服務器訪問日誌僅包含負載均衡器的IP地址。要查看客戶端的IP地址,請使用X-Forwarded-For請求標頭。

則可以使用下面的PHP代碼(假設阿帕奇)訪問:

$http_headers = apache_request_headers(); 
$original_ip = $http_headers["X-Forwarded-For"]; 
+4

如果你關心安全性,你應該阻止除ELB之外的其他任何連接。否則,攻擊者可能假裝成爲ELB,設置此標題,並向您說明真正的遠程IP地址。 http://docs.aws.amazon.com/ElasticLoadBalancing/latest/DeveloperGuide/using-elb-security-groups.html – 2013-02-28 01:14:41

+2

請注意,X-Forwarded-For標頭可以包含以逗號分隔的IP地址列表(如果存在)多個貨代。第一個是原始客戶端IP。 http://en.wikipedia.org/wiki/X-Forwarded-For#Format – mmindenhall 2014-05-19 22:27:09

+4

如果客戶端提供了自己的X-Forwarded-For,它將成爲您提供給您的以逗號分隔的IP列表中的第一個應用。顯然,真正的IP始終是最後一項。 – 2014-11-27 09:17:07

-2

你能否讓客戶明確地報告其IP地址? 檢查這個post

+0

不是。在某些情況下,客戶可能會點擊電子郵件中的鏈接。當第一次打到我們的服務器時,我們需要根據其區域確定要顯示的內容。 – BillR 2013-02-27 18:54:58

2

這是一個大問題,所以試試這個:d

<?php 
     if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) { 
      $real_client_ip = $_SERVER["HTTP_X_FORWARDED_FOR"]; 
     } else { 
      $real_client_ip = $_SERVER["REMOTE_ADDR"]; 
     } 
+0

這假定您信任客戶端提供X-Forwarded-For(即,因爲客戶端是負載均衡器)。此代碼確實應該檢查REMOTE_ADDR是否符合可接受IP的白名單,否則它會將您的代碼打開爲一個漏洞。 – ZiggyTheHamster 2016-05-11 23:44:35

8

如果你使用Apache,看看mod_remoteip模塊。它包含在Apache 2.4和更新的版本中,但是也可以找到2.2版本的backports。

模塊使用RemoteIPHeader指令配置的請求頭中報告的useragent IP地址替代連接的客戶端IP地址。

按照指示進行替換後,此重寫的useragent IP地址將用於mod_authz_host Require ip功能,由mod_status報告,並由mod_log_config%a和核心%a格式字符串記錄。連接的底層客戶端IP在%{c}格式字符串中可用。

換句話說,您可以設置使用哪個頭(例如X-Forwarded-For)和哪些IP是可信的(例如您的負載均衡器)。可信IP將從標頭中刪除,並將第一個不可信IP用作始發客戶端。這個IP然後由Apache在其他模塊內部使用,例如用於日誌記錄,主機認證等。

這使得它比僅處理PHP中的XFF頭更有用,因爲mod_remoteip負責整個堆棧,確保您的訪問日誌是正確的,等

注:還有一個mod_rpaf模塊,其前身爲這一個。它更受限制。例如,它不能處理可信的IP範圍。你需要這個,因爲你事先不知道ELB的知識產權。在Apache之前,它也無法處理多個躍點,例如Varnish之前的ELB。我建議跳過rpaf模塊並使用remoteip代替。

0

背後AWS ELB PHP應用的最佳解決方案:

if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { 
    $commaPos = strrchr($_SERVER['HTTP_X_FORWARDED_FOR'], ','); 
    if ($commaPos === FALSE) $remote_addr = $_SERVER['HTTP_X_FORWARDED_FOR']; 
    else $remote_addr = trim(substr($_SERVER['HTTP_X_FORWARDED_FOR'], $commaPos + 1)); 
} else { 
    $remote_addr = $_SERVER['REMOTE_ADDR']; 
} 

注:X-Forwarded-For可以代理的逗號空間分隔的列表,與最後列表中的是連接到AWS'ELB的列表,因此也是我們可以信任的唯一不被欺騙的列表。