# 获取真实客户端IP
#### 应用场景
客户端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再将流量转到源站，实现网站流量检测和攻击拦截。
以WAF为例，部署示意图如[图1]所示。
图1部署WAF原理图   
![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0294809832.png)
在这种情况下，访问请求到达源站服务器之前可能经过了多层安全代理转发或加速代理转发，服务器如何获取发起请求的真实客户端IP呢？
一个透明的代理服务器在把用户的HTTP请求转到下一环节的服务器时，会在HTTP的头部中加入一条"X-Forwarded-For"记录，用来记录用户的真实IP，其形式为"X-Forwarded-For：客户端的真实IP，代理服务器1-IP， 代理服务器2-IP，代理服务器3-IP，......"。
因此，您可以通过获取"X-Forwarded-For"对应的第一个IP来得到客户端的真实IP。
#### 约束条件
- 添加域名时"是否使用七层代理"配置错误将导致无法成功获取Web访问者请求的真实IP地址。 为了保证WAF的安全策略能够针对真实源IP生效，成功获取Web访问者请求的真实IP地址，如果WAF前使用了CDN、云加速等七层代理的产品，"是否使用七层代理"务必选择"是"，其他情况，"是否使用七层代理"选择"否"。
  
- 常规情况下，X-Forwarded-For字段中，第一个IP就是真实客户端IP，当IPV6地址长度超过X-Forwarded-For字段长度限制时，将读取不到IP地址；另外，nat64下，ELB是IPv4的监听器，也读不到ipv6地址。
 
#### 通过WAF直接获取真实客户端IP
网站接入WAF后，WAF作为一个反向代理部署于客户端和服务器之间，实现网站安全防护。WAF获取真实IP原则如下：
- 在WAF中开启了代理，即添加域名时，"是否使用七层代理"选择了"是"，按以下顺序获取客户端IP：
  1. 优先取"upstream"中配置的客户端IP头列表，即在域名的基本信息页面配置的"IP标记"，具体的操作请参见[配置攻击惩罚的流量标识](https://support.huaweicloud.com/usermanual-waf/waf_01_0270.html)。如果未取到，执行[2]。
     如果想以TCP连接IP作为客户端IP，"IP标记"应配置为"remote_addr"。
     
  
  2. 取config中配置的客户端IP头列表"cdn-src-ip"字段对应的值，未取到，执行[3]。
  
  3. 取"x-real-ip"字段的值，未取到，执行[4]。
  
  4. 取"x-forwarded-for"字段左边开始第一个公网IP，未取到，执行[5]。
  
  5. 取WAF看到的TCP连接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"字段，格式如下：
  ```
  X-Forwarded-For: 用户真实IP, 代理服务器1-IP， 代理服务器2-IP，...
  ```
  当使用此方式获取真实客户端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地址。
1. 打开"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" />
   ```
   
   
2. 在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>
   ```
   
   
3. 查看"localhost_access_log"日志文件，可获取**X-Forwarded-For**对应的访问者真实IP。
 
#### Apache如何在访问日志中获取真实客户端IP
如果源站部署的Apache服务器为2.4及以上版本，您可以使用Apache安装包中自带"remoteip_module"模块文件"mod_remoteip.so"，获取客户端IP地址。
- CentOS 7.6
  1. 编辑"httpd.conf"配置文件，在文件中添加以下内容：
     ```
     LoadModule remoteip_module modules/mod_remoteip.so  ##加载mod_remoteip.so模块
     RemoteIPHeader X-Forwarded-For   ##设置RemoteIPHeader头部
     RemoteIPInternalProxy WAF的回源IP段  ##设置WAF回源IP段
     ```
     有关获取WAF回源IP段的详细介绍，请参见[如何放行WAF回源IP段](https://support.huaweicloud.com/waf_faq/waf_01_0095.html)。
     - "mod_remoteip.so"模块已默认加载在以下文件："/etc/httpd/conf.modules.d/00-base.conf:46"
     
     - 多个回源IP段请使用空格分隔。
      
  
  2. 修改配置文件日志格式，即将日志格式文件中的"%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
     ```
     
  
  3. 重启Apache服务，使配置生效。
   

- Ubuntu 20.04.2
  1. 编辑"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段
     ```
     有关获取WAF回源IP段的详细介绍，请参见[如何放行WAF回源IP段](https://support.huaweicloud.com/waf_faq/waf_01_0095.html)。
     - 您也可以添加以下内容加载mod_remoteip.so模块： **LoadModule remoteip_module /usr/lib/apache2/modules/mod_remoteip.so**
       
     
     - 多个回源IP段请使用空格分隔。
      
  
  2. 修改配置文件日志格式，即将日志格式文件中的"%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
     ```
     
  
  3. 重启Apache服务，使配置生效。
   
如果源站部署的Apache服务器为2.2及以下版本，您可通过运行命令安装Apache的第三方模块mod_rpaf，并修改"http.conf"文件获取客户IP地址。
1. 执行以下命令安装Apache的一个第三方模块mod_rpaf。 
   ```
   wget https://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
   ```
   
   
2. 打开"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>
   ```
   
   
3. 定义日志格式。 
   ```
   LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" common
   ```
   
   
4. 启用自定义格式日志。 
   ```
   CustomLog "/[apache目录]/logs/$access.log" common
   ```
   
   
5. 重启Apache，使配置生效。 
   ```
   /[apached目录]/httpd/bin/apachectl restart
   ```
   
   
6. 查看"access.log"日志文件，可获取**X-Forwarded-For**对应的真实客户端IP。
 
#### Nginx如何在访问日志中获取真实客户端IP
- 如果您的源站部署了Nginx反向代理，可通过在Nginx反向代理配置Location信息，后端Web服务器即可通过类似函数获取客户的真实IP地址。
  1. 根据源站Nginx反向代理的配置，在Nginx反向代理的相应location位置配置如下内容，获取客户IP的信息。
     ```
     Location ^ /<uri> {
         proxy_pass  ....;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
     }
     ```
     
  
  2. 后端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" ';
     ```
     
   
- 如果您的源站部署了Nginx服务，可通过启用Nginx的ngx_http_realip_module模块，获取客户端的真实IP地址。
  1. 打开Nginx配置文件nginx.conf，支持两种配置位置，按需选择其一：
     - 配置在"http{}"块：对本机全部虚拟主机全局生效；
     
     - 配置在业务对应的"server{}"块：仅对当前站点生效，多业务隔离场景推荐。
     
     
     添加如下配置内容：
     ```
     # 配置WAF回源IP/网段，多条回源地址重复填写set_real_ip_from 
     set_real_ip_from <WAF回源IP段1>; 
     set_real_ip_from <WAF回源IP段2>; 
     # 指定从X‑Forwarded‑For请求头读取IP链路 
     real_ip_header X-Forwarded-For; 
     # 开启递归模式，自动剔除信任代理IP，提取原始客户端IP 
     real_ip_recursive on;
     ```
     有关获取WAF回源IP段的详细介绍，请参见[如何放行WAF回源IP段](https://support.huaweicloud.com/waf_faq/waf_01_0095.html)。
     
  
  2. 使配置生效，二选一执行：
     - 热重载（推荐，不中断现有业务连接）
       ```
       nginx -s reload
       ```
       
     
     - 完整重启（会断开现有连接，建议在业务维护窗口执行）
       ```
       systemctl restart nginx
       ```
       
      
   
 
#### IIS 6如何在访问日志中获取真实客户端IP
如果您的源站部署了IIS 6服务器，您可以通过安装"F5XForwardedFor.dll"插件，从IIS 6服务器记录的访问日志中获取真实客户端的IP地址。
1. 下载**F5XForwardedFor**模块。
2. 根据您服务器的操作系统版本将"x86\\Release"或者"x64\\Release"目录中的"F5XForwardedFor.dll"文件拷贝至指定目录（例如，"C:\\ISAPIFilters"），同时确保IIS进程对该目录有读取权限。
3. 打开IIS管理器，找到当前开启的网站，在该网站上右键选择"属性"，打开"属性"页面。
4. 在"属性"页面，切换至"ISAPI筛选器"，单击"添加"，在弹出的窗口中，配置如下信息： 
   - "筛选器名称"："F5XForwardedFor"；
   
   - "可执行文件"："F5XForwardedFor.dll"的完整路径，例如："C:\\ISAPIFilters\\F5XForwardedFor.dll"。
   
   
   
   
5. 单击"确定"，重启IIS 6服务器。
6. 查看IIS 6服务器记录的访问日志（默认的日志路径为："C:\\WINDOWS\\system32\\LogFiles\\ "，IIS日志的文件名称以".log"为后缀），可获取**X-Forwarded-For**对应的真实客户端IP。
 
#### IIS 7如何在访问日志中获取真实客户端IP
如果您的源站部署了IIS 7服务器，您可以通过安装"F5XForwardedFor"模块，从IIS 7服务器记录的访问日志中获取真实客户端的IP地址。
1. 下载**F5XForwardedFor**模块。
2. 根据服务器的操作系统版本将"x86\\Release"或者"x64\\Release"目录中的"F5XFFHttpModule.dll"和"F5XFFHttpModule.ini"文件拷贝到指定目录（例如，"C:\\x_forwarded_for\\x86"或"C:\\x_forwarded_for\\x64"），并确保IIS进程对该目录有读取权限。
3. 在IIS服务器的选择项中，双击"模块"，进入"模块"界面。
4. 单击"配置本机模块"，在弹出的对话框中，单击"注册"。 
   图2注册模块   
   ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0294788481.png)
   
   
5. 在弹出的对话框中，按操作系统注册已下载的DLL文件后，单击"确定"。 
   - x86操作系统：注册模块"x_forwarded_for_x86"
     - 名称：x_forwarded_for_x86
     
     - 路径："C:\\x_forwarded_for\\x86\\F5XFFHttpModule.dll"
     
     
     图3x86操作系统注册模块   
     ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0294795243.png) 
   
   - x64操作系统：注册模块"x_forwarded_for_x64"
     - 名称：x_forwarded_for_x64
     
     - 路径："C:\\x_forwarded_for\\x64\\F5XFFHttpModule.dll"
     
     
     图4x64操作系统注册模块   
     ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0294795548.png) 
   
   
   
   
6. 注册完成后，勾选新注册的模块（"x_forwarded_for_x86"或"x_forwarded_for_x64"）并单击"确定"。
7. 在"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
      
   
   
   
   
8. 重启IIS 7服务器，等待配置生效。
9. 查看IIS 7服务器记录的访问日志（默认的日志路径为："C:\\WINDOWS\\system32\\LogFiles\\ "，IIS日志的文件名称以".log"为后缀），可获取**X-Forwarded-For**对应的真实客户端IP。
 
#### IIS 10如何在访问日志中获取真实客户端IP
如果您的源站部署了IIS 10服务器，您可以从IIS 10服务器记录的访问日志中获取真实客户端的IP地址。IIS 10原生支持将请求头字段直接写入日志，无需安装任何第三方模块。
1. 单击开始菜单，搜索 "IIS" 或 "Internet Information Services"后，单击筛选出的"Internet Information Services (IIS)管理器"。 
   图5Internet Information Services (IIS)管理器   
   ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0000002731895711.png "点击放大")
   
   
2. 打开**IIS 管理器** 后，选择您的站点，并双击"日志"。
   
   图6打开日志   
   ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0000002702336428.png "点击放大")
   
   
3. 单击"选择字段..."后，单击"添加字段..."，并添加以下自定义字段。 
   
   | **字段名称**      | **源类型**        | **源**              |
   |:---|:---|:---|
   | X-Forwarded-For | Request Header | X-Forwarded-For |
      
   图7添加X-Forwarded-For字段   
   ![](https://support.huaweicloud.com/bestpractice-waf/zh-cn_image_0000002702176502.png "点击放大")
   
   
4. 单击"应用"，使配置生效。 
   查看IIS 10服务器记录的访问日志（默认的日志路径为："C:\\inetpub\\logs\\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地址。
您可以参考以下步骤，对云容器引擎配置文件进行修改。
1. 执行以下命令修改配置文件"kube-system/nginx-configuration"。 
   ```
   kubectl -n kube-system edit cm nginx-configuration
   ```
   
   
2. 在配置文件中添加以下内容： 
   ```
   compute-full-forwarded-for: "true"
   forwarded-for-header: "X-Forwarded-For" 
   use-forwarded-headers: "true"
   ```
   
   
3. 保存配置文件。 
   保存后配置即刻生效，Ingress会将真实的客户端IP添加到X-Forwarded-For字段中。
   
   
4. 将业务程序获取真实客户端IP的字段修改为X-Original-Forwarded-For。
 
