跳转到帖子

咖啡馆实战:反向代理真实客户端 IP 配置不当导致后台权限绕过的排查与修复

精选回复

发布于

背景

网站接入 CDN、WAF 或四层负载均衡后,源站看到的连接地址通常是代理节点 IP。为了恢复访客地址,运维人员会在 Nginx 中启用 realip 模块,再通过 X-Forwarded-For、X-Real-IP 或厂商专用请求头获取客户端 IP。

这类配置直接影响访问控制和日志取证。如果源站无条件信任外部传入的地址头,而后台接口又使用客户端 IP 判断内网权限,攻击者可能在无需进入内网的情况下伪造地址并绕过限制。下面以授权测试环境中的 Nginx 反向代理为例说明完整排查过程。

典型场景

测试环境链路如下:

互联网客户端 -> CDN/WAF -> Nginx 源站 -> Web 应用

/admin 访问规则:
仅允许 127.0.0.1 或 10.0.0.0/8 来源访问

源站存在如下配置:

set_real_ip_from 0.0.0.0/0;
real_ip_header X-Real-IP;
real_ip_recursive on;

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass 
}

问题不在于启用了 realip,而在于 set_real_ip_from 0.0.0.0/0 将任意来源都定义为可信代理。外部请求只要携带 X-Real-IP,Nginx 就可能使用该值重写 $remote_addr。应用最终看到的是攻击者指定的地址。

问题定位

先确认请求是否能够绕过 CDN 直接到达源站。只要源站公网端口开放,即使正常域名已经接入 CDN,攻击者仍可能通过历史 DNS、证书透明度记录或资产测绘找到源站地址。

# 检查 Nginx 实际监听地址
ss -lntp | grep -E ':80|:443'

# 展开全部 Nginx 配置,避免只检查主配置文件
nginx -T 2>&1 | grep -nE 'set_real_ip_from|real_ip_header|real_ip_recursive|proxy_set_header|allow|deny'

# 检查 realip 模块是否已编译
nginx -V 2>&1 | grep http_realip_module

如果源站地址已知,可以在获得授权后固定解析进行验证,避免修改公共 DNS:

# 正常请求,预期返回 403
curl -k -i --resolve test.example:443:192.0.2.10 \
  

# 伪造真实地址头,仅用于授权测试环境
curl -k -i --resolve test.example:443:192.0.2.10 \
  -H 'X-Real-IP: 127.0.0.1' \
  

# 再使用普通公网测试地址做对照
curl -k -i --resolve test.example:443:192.0.2.10 \
  -H 'X-Real-IP: 198.51.100.23' \
   403,而第二条变为 200,基本可以确认地址头参与了权限判断。验证时不能只比较状态码,还应核对响应长度、重定向位置和应用日志,排除缓存或统一错误页面造成的误判。

技术分析

Nginx 启用 realip 后,几个变量的含义容易混淆:

  • $remote_addr:经过 realip 处理后的客户端地址,可能来自请求头。
  • $realip_remote_addr:建立 TCP 连接的原始对端地址,适合保留代理节点或直连来源。
  • $proxy_add_x_forwarded_for:将当前 $remote_addr 追加到已有 X-Forwarded-For。若上游传入值未被可信入口清洗,错误链路可能继续传递到应用。
  • $proxy_protocol_addr:仅在前端负载均衡启用并正确发送 PROXY protocol 时有效,不能与普通 HTTP 地址头混为一谈。

更隐蔽的情况是 Nginx 自身配置正确,但后端框架再次解析 X-Forwarded-For,并直接取最左侧地址。例如应用收到以下内容:

X-Forwarded-For: 127.0.0.1, 203.0.113.20

如果应用把最左侧地址视为真实来源,攻击者仍可能影响权限判断。因此需要同时检查 Nginx 和应用框架的代理信任设置,例如 Express 的 trust proxy、Django 的代理头处理、中间件自定义 getClientIp 函数以及 Java 网关的 ForwardedHeaderFilter。

完善日志留痕

默认日志如果只记录 $remote_addr,发生伪造后会直接写入假地址,不利于复盘。建议同时记录 TCP 对端、解析后的客户端地址、转发链和上游响应信息:

# 放在 http 上下文
log_format proxy_trace escape=json
  '{'
  '"time":"$time_iso8601",'
  '"request_id":"$request_id",'
  '"peer_ip":"$realip_remote_addr",'
  '"client_ip":"$remote_addr",'
  '"xff":"$http_x_forwarded_for",'
  '"x_real_ip":"$http_x_real_ip",'
  '"host":"$host",'
  '"request":"$request",'
  '"status":$status,'
  '"upstream":"$upstream_addr",'
  '"upstream_status":"$upstream_status",'
  '"request_time":$request_time,'
  '"upstream_time":"$upstream_response_time"'
  '}';

access_log /var/log/nginx/proxy_trace.log proxy_trace;

修改后先执行语法检查,再平滑加载:

nginx -t && nginx -s reload

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

# 使用 jq 检查 TCP 对端与解析后地址不一致的记录
jq -c 'select(.peer_ip != .client_ip)' \
  /var/log/nginx/proxy_trace.log

peer_ip 与 client_ip 不一致不一定代表攻击,因为经过可信 CDN 时这是正常现象。排查重点是 peer_ip 不属于代理节点网段,但 client_ip 却是回环、内网或管理网地址的记录。

安全配置方法

第一步是只信任实际存在的反向代理网段,不要使用 0.0.0.0/0。以下地址仅为文档示例,生产环境应使用 CDN 或负载均衡厂商发布并维护的真实网段:

# 只信任明确的代理节点
set_real_ip_from 192.0.2.0/24;
set_real_ip_from 2001:db8:100::/48;

real_ip_header X-Forwarded-For;
real_ip_recursive on;

如果 CDN 提供专用地址头,应确认该请求头只可能由可信节点写入。源站仍需限制直连,否则攻击者可以绕过 CDN 自行构造同名请求头。

第二步是在安全组、防火墙或边界负载均衡上限制源站入口。以主机防火墙为例,应先确认远程管理链路,避免误封 SSH:

# 示例逻辑:仅允许代理网段访问 HTTPS
iptables -A INPUT -p tcp -s 192.0.2.0/24 --dport 443 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j DROP

# 检查实际规则与计数器
iptables -L INPUT -n -v --line-numbers

云环境中优先使用安全组、负载均衡后端策略或经过认证的源站回源机制。条件允许时,可在 CDN 与源站之间部署双向 TLS,避免仅依赖来源 IP。

第三步是规范向后端传递的地址。后端如果没有解析完整代理链的必要,可以传递一个由 Nginx 统一计算的受控请求头:

location / {
    proxy_set_header X-Client-IP $remote_addr;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
    proxy_pass 
}

应用只读取 X-Client-IP 的前提是应用端口不能被外部直接访问,并且该请求头只能由受控 Nginx 写入。否则只是把信任问题换了一个名字。

权限边界与修复建议

  • 不要把来源 IP 当作后台登录的唯一认证条件。管理接口仍应启用身份认证、角色授权和必要的多因素认证。
  • 内网地址只适合作为附加限制,不能代替会话鉴权。尤其不要用字符串前缀判断 10.、127. 或 192.168.。
  • 限制应用监听范围。单机部署可监听 127.0.0.1,多主机部署则通过安全组只允许反向代理访问后端端口。
  • 定期同步 CDN 地址段,并在变更前执行配置测试。过期网段既可能造成业务中断,也可能继续信任已被释放的地址资源。
  • 审计应用代码中对 X-Forwarded-For、X-Real-IP、Forwarded 和自定义客户端地址头的读取位置。
  • 告警规则应关注外部 TCP 对端提交内网地址、回环地址、链路地址,以及同一对端频繁切换客户端地址的行为。
  • 保留 request_id,并让 Nginx、网关和应用日志使用同一关联标识,便于还原完整请求链路。

修复后的回归验证

修复后至少覆盖三组测试:通过正常 CDN 访问时能够获得正确客户端地址;直接访问源站时被网络层拒绝;伪造地址头时不能改变权限结果。还应确认健康检查、证书续期和监控节点没有被新的入口策略误伤。

# 配置检查
nginx -t

# 通过正常入口访问
curl -k -i 

# 通过源站直连并伪造头,预期连接失败或仍返回 403
curl -k -i --resolve test.example:443:192.0.2.10 \
  -H 'X-Real-IP: 127.0.0.1' \
  -H 'X-Forwarded-For: 127.0.0.1' \
   IP 配置本质上是信任边界配置。排查时不能只看某一个请求头,需要同时确认源站是否可直连、哪些代理地址被信任、Nginx 如何重写变量、后端框架如何再次解析以及日志是否保留原始 TCP 对端。可靠的修复方式是收紧代理信任范围、限制源站入口、统一地址传递规则,并让管理接口使用独立的身份认证与授权机制。

服务器与云环境安全示意图
服务器、云资产与权限边界梳理示意
网络流量与边界分析示意图
网络请求、日志与边界流量分析示意

这类绕过通常不是“取错了 IP”这么简单,而是应用无条件信任了客户端可控的 X-Forwarded-For,再叠加“内网 IP 可访问后台”的授权逻辑。建议按请求链逐跳确认:客户端 → CDN/LB → Nginx → 应用,明确只有哪一层有资格写真实客户端 IP。

如果 Nginx 是唯一入口,应只信任实际代理节点网段,并让 realip 模块从右向左剥离可信代理:

set_real_ip_from 10.20.0.0/16;       # 实际 LB 网段
set_real_ip_from 192.168.50.10/32;    # 实际反代地址
real_ip_header X-Forwarded-For;
real_ip_recursive on;

location / {
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header Host $host;
    proxy_pass 
}

不要配置成 set_real_ip_from 0.0.0.0/0,也不要直接在应用里取 X-Forwarded-For 的第一个值作为客户端地址。若公网请求可以绕过 Nginx 直连后端,还需要在安全组或防火墙上封掉后端端口,只允许反代节点访问。

可以用下面几组请求快速复现和验证:

# 伪造内网地址,修复后不应获得后台权限
curl -i  \
  -H 'X-Forwarded-For: 127.0.0.1'

curl -i  \
  -H 'X-Forwarded-For: 10.0.0.8, 127.0.0.1'

# 同时检查 IPv6 和等价表示
curl -i  \
  -H 'X-Forwarded-For: ::1'

排查日志时最好同时记录连接来源、解析后的地址和原始转发头,避免只看到被改写后的变量:

log_format realip '$remote_addr realip_remote=$realip_remote_addr '
                  'xff="$http_x_forwarded_for" request="$request" status=$status';
access_log /var/log/nginx/access.log realip;

应用层也要检查框架的代理信任配置。例如 Express 不要写成无条件信任:

// 仅信任明确的反代网段
app.set('trust proxy', ['loopback', '10.20.0.0/16']);

// 不建议:app.set('trust proxy', true);

更关键的是,后台权限不要以来源 IP 作为唯一授权条件。IP 白名单最多作为附加限制,实际访问仍应要求登录态、角色权限和必要的二次认证。咖啡馆、公网 NAT、VPN、代理链都会让基于 IP 的身份判断变得不可靠。修复后还应回查访问日志,搜索伪造的私网、回环地址以及异常多段 X-Forwarded-For,确认是否已经发生过利用。

创建帐户或登录后发表意见

最近浏览 0

  • 没有会员查看此页面。

SiteMap HACKHAT © 2026 All rights reserved.