應用場景
客戶端IP指的是訪問者(用戶設備)的IP地址。在Web應用開發中,通常需要獲取客戶端真實的IP地址。例如,投票系統為了防止刷票,需要通過獲取客戶端真實IP地址,限制每個客戶端IP地址只能投票一次。
當您的網站已接入Web應用防火墻(Web Application Firewall,簡稱WAF)進行安全防護后,WAF作為一個反向代理存在于客戶端和服務器之間,服務器的真實IP被隱藏起來,Web訪問者只能看到WAF的IP地址。此時,您可直接通過WAF獲取客戶端的真實IP,也可以通過配置網站服務器獲取客戶端的真實IP。
本章節介紹了通過WAF直接獲取真實IP的方法,以及不同類型的Web應用服務器(包括Tomcat、Apache、Nginx、IIS 6和IIS 7)如何進行相關設置,以獲取客戶端的真實IP。
方案架構
通常情況下,網站訪問并不是簡單地從用戶的瀏覽器直達服務器,中間可能部署有CDN、WAF、高防等代理服務器(架構為“用戶> CDN/WAF/高防等代理服務 > 源站服務器”)。
說明
當網站沒有接入到WAF前,DNS直接解析到源站的IP,用戶直接訪問服務器。
當網站接入WAF后,需要把DNS解析到WAF的CNAME,這樣流量才會先經過WAF,WAF再將流量轉到源站,實現網站流量檢測和攻擊攔截。
在這種情況下,訪問請求到達源站服務器之前可能經過了多層安全代理轉發或加速代理轉發,服務器如何獲取發起請求的真實客戶端IP呢?
一個透明的代理服務器在把用戶的HTTP請求轉到下一環節的服務器時,會在HTTP的頭部中加入一條“X-Forwarded-For”記錄,用來記錄用戶的真實IP,其形式為“X-Forwarded-For:客戶端的真實IP,代理服務器1-IP, 代理服務器2-IP,代理服務器3-IP,……”。
因此,您可以通過獲取“X-Forwarded-For”對應的第一個IP來得到客戶端的真實IP。
約束條件
添加域名時配置錯誤將導致無法成功獲取Web訪問者請求的真實IP地址。
常規情況下,X-Forwarded-For字段中,第一個IP就是客戶端真實IP,當IPV6地址長度超過X-Forwarded-For字段長度限制時,將讀取不到IP地址;另外,nat64下,ELB是IPv4的監聽器,也讀不到ipv6地址。
通過WAF直接獲取客戶端真實IP
網站接入WAF后,WAF作為一個反向代理部署于客戶端和服務器之間,實現網站安全防護。
在WAF中開啟了代理,按以下順序獲取源IP:
優先取“upstream”中配置的源IP頭列表,即在域名的基本信息頁面配置的“IP標記”,具體的操作請參見配置攻擊懲罰的流量標識。如果未取到,執行 。
取WAF看到的TCP連接IP,“remote_addr”字段對應的值。
說明
如果想以TCP連接IP作為客戶端IP,“IP標記”應配置為“remote_addr”。
在WAF中未開啟代理,直接取“remote_ip”字段的值為真實IP。
下面為您介紹如何通過X-Forwarded-For和X-Real-IP變量獲取客戶端真實IP地址的方法:
WAF使用X-Forwarded-For的方式獲取客戶端的真實IP地址。
WAF將“真實的客戶端IP”放在HTTP頭部的“X-Forwarded-For”字段,格式如下:
說明
當使用此方式獲取客戶端真實IP時,獲取的第一個地址就是客戶端真實IP。
各種語言通過調用SDK接口獲取X-Forwarded-For字段的方式:
ASP:
Request.ServerVariables("HTTP_X_FORWARDED_FOR")ASP.NET(C#):
Request.ServerVariables["HTTP_X_FORWARDED_FOR"]PHP:
$_SERVER["HTTP_X_FORWARDED_FOR"]JSP:
request.getHeader("HTTP_X_FORWARDED_FOR")WAF服務還支持使用X-Real-IP變量,獲取客戶的來源IP(使用過程中考慮了后面經過的多層反向代理對該變量的修改)。
各種語言通過調用SDK接口獲取X-Real-IP字段的方式:
ASP:
Request.ServerVariables("HTTP_X_REAL_IP")ASP.NET(C#):
Request.ServerVariables["HTTP_X_REAL_IP"]PHP:
$_SERVER["HTTP_X_REAL_IP"]JSP:
request.getHeader("HTTP_X_REAL_IP")Tomcat如何在訪問日志中獲取客戶端真實IP
如果您的源站部署了Tomcat服務器,可通過啟用Tomcat的X-Forwarded-For功能,獲取客戶端的真實IP地址。
打開“server.xml”文件(“tomcat/conf/server.xml”),AccessLogValue日志記錄功能部分內容如下:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Valve className="org.apache.catalina.values.AccessLogValue" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="%h %l %u %t "%r" %s %b" />在pattern中增加“%{X-Forwarded-For}i”,修改后的server.xml為:
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValue" directory="logs"
prefix="localhost_access_log." suffix=".txt"
pattern="%{X-Forwarded-For}i %h %l %u %t "%r" %s %b" />
</Host>查看“localhost_access_log”日志文件,可獲取X-Forwarded-For對應的訪問者真實IP。
Apache如何在訪問日志中獲取客戶端真實IP
如果源站部署的Apache服務器為2.4及以上版本,您可以使用Apache安裝包中自帶“remoteip_module”模塊文件“mod_remoteip.so”,獲取客戶端IP地址。
CentOS 7.6
編輯“httpd.conf”配置文件,在文件中添加以下內容:
LoadModule remoteip_module modules/mod_remoteip.so ##加載mod_remoteip.so模塊
RemoteIPHeader X-Forwarded-For ##設置RemoteIPHeader頭部
RemoteIPInternalProxy WAF的回源IP段 ##設置WAF回源IP段 說明
“mod_remoteip.so”模塊已默認加載在以下文件:“/etc/httpd/conf.modules.d/00-base.conf:46”
多個回源IP段請使用空格分隔。
修改配置文件日志格式,即將日志格式文件中的“%h”修改為“%a”。
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %b" common重啟Apache服務,使配置生效。
Ubuntu 20.04.2
編輯“apache2.conf”配置文件,在文件中添加以下內容:
ln -s ../mods-available/remoteip.load /etc/apache2/mods-enabled/remoteip.load ##加載mod_remoteip.so模塊
RemoteIPHeader X-Forwarded-For ##設置RemoteIPHeader頭部
RemoteIPInternalProxy WAF的回源IP段 ##設置WAF回源IP段 說明
您也可以添加以下內容加載mod_remoteip.so模塊:
LoadModule remoteip_module /usr/lib/apache2/modules/mod_remoteip.so
多個回源IP段請使用空格分隔。
修改配置文件日志格式,即將日志格式文件中的“%h”修改為“%a”。
LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%a %l %u %t \"%r\" %>s %b" common 重啟Apache服務,使配置生效。
如果源站部署的Apache服務器為2.2及以下版本,您可通過運行命令安裝Apache的第三方模塊mod_rpaf,并修改“http.conf”文件獲取客戶IP地址。
執行以下命令安裝Apache的一個第三方模塊mod_rpaf。
wget //github.com/gnif/mod_rpaf/archive/v0.6.0.tar.gz
tar xvfz mod_rpaf-0.6.tar.gz
cd mod_rpaf-0.6
/usr/local/apache/bin/apxs -i -c -n mod_rpaf-2.0.so mod_rpaf-2.0.c 打開“httpd.conf”配置文件,并將文件內容修改為如下內容:
LoadModule rpaf_module modules/mod_rpaf-2.0.so ##加載mod_rpaf模塊
<IfModule mod_rpaf.c>
RPAFenable On
RPAFsethostname On
RPAFproxy_ips 127.0.0.1 <反向代理IPs>
RPAFheader X-Forwarded-For
</IfModule>定義日志格式。
LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" common 啟用自定義格式日志。
CustomLog "/[apache目錄]/logs/$access.log" common 重啟Apache,使配置生效。
/[apached目錄]/httpd/bin/apachectl restart查看“access.log”日志文件,可獲取X-Forwarded-For對應的客戶端真實IP。
Nginx如何在訪問日志中獲取客戶端真實IP
如果您的源站部署了Nginx反向代理,可通過在Nginx反向代理配置Location信息,后端Web服務器即可通過類似函數獲取客戶的真實IP地址。
根據源站Nginx反向代理的配置,在Nginx反向代理的相應location位置配置如下內容,獲取客戶IP的信息。
Location ^ /<uri> {
proxy_pass ....;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}后端Web服務器通過定義Nginx日志參數$http_x_forwarded_for來獲取客戶的真實IP。
示例:
log_format main ' "<$http_Cdn_Src_IP>" "{$http_x_real_ip}" "[$http_x_forwarded_for]" "$remote_addr" ' '$http_user_agent - $remote_user [$time_local] "$request" ' ' $status $body_bytes_sent "$http_referer" '; ----結束
IIS 6如何在訪問日志中獲取客戶端真實IP
如果您的源站部署了IIS 6服務器,您可以通過安裝“F5XForwardedFor.dll”插件,從IIS 6服務器記錄的訪問日志中獲取客戶端真實的IP地址。
下載模塊。
根據您服務器的操作系統版本將“x86\Release”或者“x64\Release”目錄中的“F5XForwardedFor.dll”文件拷貝至指定目錄(例如,“C:\ISAPIFilters”),同時確保IIS進程對該目錄有讀取權限。
打開IIS管理器,找到當前開啟的網站,在該網站上右鍵選擇“屬性”,打開“屬性”頁面。
在“屬性”頁面,切換至“ISAPI篩選器”,單擊“添加”,在彈出的窗口中,配置如下信息:
“篩選器名稱”:“F5XForwardedFor”;
“可執行文件”:“F5XForwardedFor.dll”的完整路徑,例如:“C:\ISAPIFilters\F5XForwardedFor.dll”。
單擊“確定”,重啟IIS 6服務器。
查看IIS 6服務器記錄的訪問日志(默認的日志路徑為:“C:\WINDOWS\system32\LogFiles\ ”,IIS日志的文件名稱以“.log”為后綴),可獲取X-Forwarded-For對應的客戶端真實IP。
IIS 7如何在訪問日志中獲取客戶端真實IP
如果您的源站部署了IIS 7服務器,您可以通過安裝“F5XForwardedFor”模塊,從IIS 7服務器記錄的訪問日志中獲取客戶端真實的IP地址。
下載模塊。
根據服務器的操作系統版本將“x86\Release”或者“x64\Release”目錄中的“F5XFFHttpModule.dll”和“F5XFFHttpModule.ini”文件拷貝到指定目錄(例如,“C:\x_forwarded_for\x86”或“C:\x_forwarded_for\x64”),并確保IIS進程對該目錄有讀取權限。
在IIS服務器的選擇項中,雙擊“模塊”,進入“模塊”界面。
單擊“配置本機模塊”,在彈出的對話框中,單擊“注冊”。
在彈出的對話框中,按操作系統注冊已下載的DLL文件后,單擊“確定”。
x86操作系統:注冊模塊“x_forwarded_for_x86”
- 名稱:x_forwarded_for_x86
- 路徑:“C:\x_forwarded_for\x86\F5XFFHttpModule.dll”
x64操作系統:注冊模塊“x_forwarded_for_x64”
- 名稱:x_forwarded_for_x64
- 路徑:“C:\x_forwarded_for\x64\F5XFFHttpModule.dll”
注冊完成后,勾選新注冊的模塊(“x_forwarded_for_x86”或“x_forwarded_for_x64”)并單擊“確定”。
在“ISAPI和CGI限制”中,按操作系統添加已注冊的DLL文件,并將其“限制”改為“允許”。
x86操作系統:
- ISAPI或CGI路徑:“C:\x_forwarded_for\x86\F5XFFHttpModule.dll”
- 描述:x86
x64操作系統:
- ISAPI或CGI路徑:“C:\x_forwarded_for\x64\F5XFFHttpModule.dll”
- 描述:x64
重啟IIS 7服務器,等待配置生效。
查看IIS 7服務器記錄的訪問日志(默認的日志路徑為:“C:\WINDOWS\system32\LogFiles\ ”,IIS日志的文件名稱以“.log”為后綴),可獲取X-Forwarded-For對應的客戶端真實IP。
云容器引擎如何獲取客戶端真實IP
如果您的服務部署在云容器引擎(Cloud Container Engine,簡稱CCE)上,云容器引擎會將真實的客戶端IP記錄在X-Original-Forwarded-For字段中,并將WAF回源地址記錄在X-Forwarded-For字段中。您需要修改云容器引擎的配置文件,使Ingress將真實的IP添加到X-Forwarded-For字段中,以便您正常獲取真實的客戶端IP地址。
您可以參考以下步驟,對云容器引擎配置文件進行修改。
執行以下命令修改配置文件“kube-system/nginx-configuration”。
kubectl -n kube-system edit cm nginx-configuration在配置文件中添加以下內容:
compute-full-forwarded-for: "true"
forwarded-for-header: "X-Forwarded-For"
use-forwarded-headers: "true"保存配置文件。
保存后配置即刻生效,Ingress會將真實的客戶端IP添加到X-Forwarded-For字段中。
將業務程序獲取客戶端真實IP的字段修改為X-Original-Forwarded-For。