通过 HTTP 请求头获取客户端真实 IP

更新时间:
复制 MD 格式

CNAME 接入 Web应用防火墙(Web Application Firewall,简称WAF) 时,源站收到的请求源 IP 为最后一跳代理地址而非客户端真实 IP。WAF 通过在 HTTP 请求头中插入 X-Forwarded-For 字段传递真实 IP。本文介绍如何在各后端 Web 服务器配置,从该字段提取客户端真实 IP,以确保日志记录和安全审计正常工作。

工作原理

CNAME 接入 WAF 后,客户端请求先经过 WAF 及可能存在的其他中间代理(如 CDN、DDoS 高防等),再转发至源站。此时源站接收到的 TCP 连接源 IP 为最后一跳代理的 IP,而非客户端真实 IP。

WAF 转发 HTTP 请求时会自动添加 X-Forwarded-For 头部字段。该字段初始值为客户端 IP;每经过一个代理节点,该节点的 IP 会被追加至末尾,格式如下:

X-Forwarded-For: 客户端IP, 代理1IP, 代理2IP, …

因此,需要在后端 Web 服务器配置从 X-Forwarded-For 头部提取最左侧的 IP 地址(即原始客户端 IP)。以下分别介绍各平台的配置方法。

步骤一:获取 WAF 回源 IP 段

登录Web应用防火墙控制台,在顶部菜单栏选择 WAF 实例的资源组和地域(中国内地非中国内地),单击接入管理 > CNAME接入 > Web应用防火墙回源IP网段列表 ,记录所有 WAF 回源 IP 段,供后续配置使用。

步骤二:配置源站服务器

重要

配置前请通过 ECS 快照或配置文件备份等方式完成环境备份,避免配置丢失。

Nginx 配置方案

Nginx 使用 http_realip_module 模块解析 X-Forwarded-For。按以下步骤修改 Nginx 配置。

检查是否已安装 http_realip_module

登录服务器并执行以下命令:

nginx -V 2>&1 | grep -o with-http_realip_module
说明

通过 yum install nginxapt install nginx 安装的版本通常包含该模块。自定义编译版本或极简镜像可能缺失。

添加 realip 模块(仅缺失时适用)

方式一:通过系统包管理器重新安装

# Alibaba Cloud Linux / CentOS / RHEL
sudo yum reinstall nginx -y
# Ubuntu / Debian
sudo apt install --reinstall nginx-core nginx-full

方式二:源码编译

  1. 安装依赖。

    # Alibaba Cloud Linux / CentOS / RHEL
    sudo yum install -y gcc pcre-devel zlib-devel openssl-devel
    # Ubuntu / Debian
    sudo apt update
    sudo apt install -y build-essential libpcre3-dev zlib1g-dev libssl-dev
  2. 查看已安装的 Nginx 版本。

    # 查看版本(用于下载对应源码)
    nginx -v
    # 查看完整编译参数
    nginx -V 2>&1 | grep 'configure arguments' | sed 's/configure arguments: //'

    记录输出内容,例如 --prefix=/usr/local/nginx --with-http_ssl_module --with-http_v2_module

  3. 下载对应版本的 Nginx 源码,请替换为实际版本号。

    cd /tmp
    wget http://nginx.org/download/nginx-1.26.0.tar.gz
    tar zxvf nginx-1.26.0.tar.gz
    cd nginx-1.26.0
  4. 配置编译选项,将步骤 2 中的原始参数复制,并在末尾追加 --with-http_realip_module

    ./configure \
      --prefix=/usr/local/nginx \
      --with-http_ssl_module \
      --with-http_v2_module \
      --with-http_realip_module
  5. 编译并升级服务。

    make
    #  make后会在 objs/ 目录下生成新的 nginx 二进制文件。
    #  重命名旧二进制(保留备份)
    sudo mv /usr/local/nginx/sbin/nginx /usr/local/nginx/sbin/nginx.old
    #  替换为新编译的版本
    sudo cp objs/nginx /usr/local/nginx/sbin/nginx
    # 获取当前主进程 PID
    OLD_PID=$(pgrep -f 'nginx: master' | head -1)
    # 启动新主进程
    sudo kill -USR2 $OLD_PID
    # 等待新进程启动
    sleep 2
    # 关闭旧进程
    sudo kill -QUIT $OLD_PID

配置 Nginx 信任 WAF 回源 IP 段

  1. 编辑 nginx.conf 主配置文件(默认位于 /etc/nginx/nginx.conf),在 http {} 块中添加以下内容。

    http {
      # 信任来自 WAF 回源 IP 的 X-Forwarded-For 头
      # 请替换为实际从控制台获取的 WAF 回源 IP 段,每个网段单独一行
      # 必须包含全部 WAF 回源网段,若有遗漏,则可能导致日志仍显示 WAF 的回源IP,而非客户端真实 IP。
      set_real_ip_from    <ip_range1>;    
      set_real_ip_from    <ip_range2>;   
      ...
      set_real_ip_from    <ip_rangex>;
      # 指定从X-Forwarded-For请求头提取真实 IP
      real_ip_header      X-Forwarded-For;
    }
  2. 重载 Nginx 配置:

    nginx -t && nginx -s reload

验证

  1. 访问网站,将 http://your-domain.com/ 替换为已接入 WAF 的域名。

    curl http://your-domain.com/
  2. 查看 Nginx 访问日志,应显示客户端真实 IP 地址。

    tail -f /var/log/nginx/access.log

IIS 7 配置方案(IIS 7 及以上版本适用)

WAF 作为反向代理时,IIS 默认日志中的 c-ip 字段记录的是 WAF 回源 IP 而非真实用户 IP。通过 IIS 的 W3C 自定义日志字段功能,可将 X-Forwarded-For 请求头写入日志,便于审计和排查。

  1. 打开 IIS 管理器,在左侧连接树中展开服务器节点,选择目标网站(例如 Default Web Site)。

  2. 双击右侧功能视图中的日志图标。

  3. 日志文件区域,确认日志格式W3C(默认值)。若为其他格式,请切换为 W3C。

  4. 日志文件区域,单击选择字段…

  5. 在弹出窗口底部,单击添加字段…

  6. 添加自定义字段对话框中填写以下信息,单击确定。

    配置项

    配置说明

    字段名称

    填写 X-FORWARDED-FOR

    源类型

    选择 请求标头

    填写 X-Forwarded-For

  7. 单击确定保存自定义字段。

  8. 再次单击确定关闭日志记录字段窗口,然后单击右侧应用保存更改。

  9. 重启 IIS 服务器使配置生效。

  10. 访问网站进行验证,并查看访问日志(默认路径 C:\inetpub\logs\LogFiles\W3SVC1\),应显示真实客户端 IP 地址。

Apache 配置方案

Apache 2.4 及以上版本自带 remoteip_module 模块(mod_remoteip.so),使用该模块可获取客户端真实 IP。

Alibaba Cloud Linux / CentOS / RHEL

  1. 编辑 Apache 主配置文件。

    sudo vim /etc/httpd/conf/httpd.conf
  2. 在文件末尾添加以下内容。

    # 启用 mod_remoteip
    LoadModule remoteip_module modules/mod_remoteip.so
    # 指定 WAF 传递真实 IP 的请求头(WAF 使用 X-Forwarded-For)
    RemoteIPHeader X-Forwarded-For
    # 设置WAF回源IP段 请务必替换为阿里云 WAF 的回源 IP 段
    RemoteIPTrustedProxy 100.xx.xx.0/10
    RemoteIPTrustedProxy 11.xx.xx.0/13
    RemoteIPTrustedProxy 112.xx.xx.0/16
  3. 定位至配置文件的日志格式部分,将 %h 改为 %a%a 表示连接的远程 IP(经 mod_remoteip 修正后的真实客户端 IP),%h 为原始连接 IP(即 WAF 节点 IP)。修改后的示例如下所示。

    <IfModule log_config_module>
        #
        # The following directives define some format nicknames for use with
        # a CustomLog directive (see below).
        #
        LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
        LogFormat "%a %l %u %t \"%r\" %>s %b" common
        <IfModule logio_module>
          # You need to enable mod_logio.c to use %I and %O
          LogFormat "%a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
        </IfModule>
        #
        # The location and format of the access logfile (Common Logfile Format).
        # If you do not define any access logfiles within a <VirtualHost>
        # container, they will be logged here.  Contrariwise, if you *do*
        # define per-<VirtualHost> access logfiles, transactions will be
        # logged therein and *not* in this file.
        #
        #CustomLog "logs/access_log" common
        #
        # If you prefer a logfile with access, agent, and referer information
        # (Combined Logfile Format) you can use the following directive.
        #
        CustomLog "logs/access_log" combined
    </IfModule>
  4. 重启 Apache 服务使配置生效。

    sudo systemctl restart httpd
  5. 访问网站进行验证,并查看访问日志,应显示真实客户端 IP 地址。

    tail -f /var/log/httpd/access_log

Ubuntu / Debian

  1. 启用 remoteip 模块。

    sudo a2enmod remoteip
  2. 编辑 Apache 主配置文件。

    sudo vim /etc/apache2/apache2.conf
  3. 在文件末尾添加以下内容。

    # 指定 WAF 传递真实 IP 的请求头(WAF 使用 X-Forwarded-For)
    RemoteIPHeader X-Forwarded-For
    # 设置WAF回源IP段 请务必替换为阿里云 WAF 的回源 IP 段
    RemoteIPTrustedProxy 100.xx.xx.0/10
    RemoteIPTrustedProxy 11.xx.xx.0/13
    RemoteIPTrustedProxy 112.xx.xx.0/16
  4. 定位至配置文件的日志格式部分,将 %h 改为 %a%a 表示连接的远程 IP(经 mod_remoteip 修正后的真实客户端 IP),%h 为原始连接 IP(即 WAF 节点 IP)。修改后的示例如下所示。

    #
    LogFormat "%v:%p %a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" vhost_combined
    LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
    LogFormat "%a %l %u %t \"%r\" %>s %O" common
    LogFormat "%{Referer}i -> %U" referer
    LogFormat "%{User-agent}i" agent
  5. 重启 Apache 服务使配置生效。

    sudo systemctl restart apache2
  6. 访问网站进行验证,并查看访问日志,应显示真实客户端 IP 地址。

    tail -f /var/log/apache2/access.log

Tomcat 配置方案

Tomcat 通过启用 X-Forwarded-For 功能获取客户端真实 IP。

  1. 前往 Tomcat 安装目录,打开 tomcat/conf/server.xml 配置文件。

  2. 将 AccessLogValve 日志配置修改为以下内容:

    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
    prefix="localhost_access_log." suffix=".txt"
    pattern="%{X-FORWARDED-FOR}i %l %u %t %r %s %b %D %q %{User-Agent}i %T" resolveHosts="false"/>
  3. 重启 Tomcat。

    sudo systemctl restart tomcat
  4. 访问网站进行验证,并查看访问日志,应显示真实客户端 IP 地址。

    # 请将以下命令替换为实际的Tomcat安装目录路径,并替换为实际的日志文件
    tail -f /opt/tomcat/logs/localhost_access_log.2026-01-01.txt 

Kubernetes 集群配置方案

使用 Nginx Ingress Controller 的 Kubernetes 集群接入 WAF 时,客户端真实 IP 会被 WAF 添加至 X-Forwarded-For 请求头。默认情况下 Nginx Ingress Controller 不信任该字段,业务容器无法获取真实客户端 IP。

按以下步骤配置 Nginx Ingress Controller。

  1. 编辑 Ingress Controller 的 ConfigMap:

    kubectl -n kube-system edit cm nginx-configuration
  2. data 字段中添加以下配置项:

    compute-full-forwarded-for: "true"
    forwarded-for-header: "X-Forwarded-For"
    use-forwarded-headers: "true"
  3. 保存并退出。配置将自动生效,无需重启 Pod。

    配置完成后,Ingress Controller 会将 X-Forwarded-For 中的第一个 IP 识别为客户端真实 IP,并在转发请求时保留该值。

进阶优化:通过自定义 Header 透传真实 IP

复杂网络架构中,依赖标准 X-Forwarded-For(XFF)头存在被伪造、多层代理 IP 混淆等风险。可通过自定义 HTTP Header 透传真实客户端 IP,提升安全性和可控性。

以下示例演示通过自定义 Header 获取真实客户端 IP。

image
  1. CDN 配置

    CDN 默认在回源请求中携带 Ali-Cdn-Real-Ip HTTP 请求头,表示客户端与 CDN 节点连接时的真实 IP。通过增加自定义出站请求头,可将该 IP 传递至 WAF。CDN 控制台配置示例如下。

    配置项

    示例

    请求头操作

    增加

    自定义请求头参数

    自定义回源请求头

    自定义请求头名称

    填写自定义名称,例如 TrueIP

    请求头值

    $http_Ali_Cdn_Real_Ip

    是否允许重复

    不允许

    规则条件

    不使用

  2. WAF 配置

    在 WAF 控制台完成以下两项配置:

    • WAF前是否有七层代理(高防/CDN等):使 WAF 正确识别真实客户端 IP。

    • 启用流量标记:使源站服务器获取真实客户端 IP。

    具体配置方法,请参见获取真实客户端信息

    配置项

    示例

    WAF前是否有七层代理(高防/CDN等)

    选择,继续选择 【推荐】取指定Header字段中的第一个IP作为客户端源IP,避免XFF伪造,填写上一步 CDN 配置中的 自定义请求头名称,例如 TrueIP

    启用流量标记

    选择 客户端真实源IP,并填写上一步 CDN 配置中的 自定义请求头名称,例如 TrueIP

  3. 源站服务器配置

    以 Nginx 为例,编辑 nginx.conf 主配置文件,在 http {} 块中添加以下内容。详情请参见Nginx 配置方案

    http {
      # 信任来自 WAF 回源 IP 的请求头
      # 请替换为实际从控制台获取的 WAF 回源 IP 段,每个网段单独一行
      # 必须包含全部 WAF 回源网段,若有遗漏,则可能导致日志仍显示 WAF 的回源IP,而非客户端真实 IP。
      set_real_ip_from    <ip_range1>;    
      set_real_ip_from    <ip_range2>;   
      ...
      set_real_ip_from    <ip_rangex>;
      # 指定从自定义的请求头提取真实 IP,本示例使用TrueIP
      real_ip_header      TrueIP;
    }

    建议在源站服务器安全组配置放行 WAF 回源 IP 段,确保仅有 WAF 能与源站通信,避免攻击者绕过 WAF 直接访问源站公网 IP。

常见问题

源站服务器的真实 IP 获取配置与 WAF 控制台中的“WAF前是否有七层代理(高防/CDN等)”配置项有什么区别?

  • 源站服务器的真实 IP 获取配置(本文内容)

    • 作用:CNAME 接入 WAF 后,使源站服务器(如 Nginx)的访问日志(如 access.log)记录真实客户端 IP,而非 WAF 回源 IP。

    • 是否必需:仅在需要在源站侧查看或处理真实客户端 IP 时才需配置。

  • WAF 控制台的WAF前是否有七层代理(高防/CDN等)配置项

    • 适用场景:WAF 前方部署了其他七层代理(如 CDN、高防等)。

    • 作用:告知 WAF 从指定 HTTP 请求头(如 Ali-Cdn-Real-IpX-Forwarded-For)中提取真实客户端 IP,确保安全报表和攻击识别基于真实来源 IP。

    • 是否必需:仅在 WAF 前存在七层代理时才需启用;若无前置代理,保持默认值

X-Forwarded-For 伪造是什么,如何避免?

X-Forwarded-For(XFF)伪造指攻击者在 HTTP 请求中构造或篡改 X-Forwarded-For 请求头,注入虚假客户端 IP,以绕过基于 IP 的访问控制、日志审计或安全策略。X-Forwarded-For 是非标准请求头,客户端可任意设置,若后端服务未经验证直接信任该字段,将带来安全风险。

示例:XFF 伪造攻击命令
攻击者可使用 curl 命令伪造 X-Forwarded-For 头,伪装 IP 为 1.2.3.4

curl -H "X-Forwarded-For: 1.2.3.4" https://example.com/

防范 XFF 伪造的方法是使用自定义可信请求头传递真实 IP:
配置 CDN 或 WAF 在回源时使用预定义的自定义 HTTP 请求头传递真实客户端 IP,源站侧仅解析该自定义头。该请求头由可信中间件(如 WAF)注入,客户端无法直接控制,可有效避免伪造。