跳转到帖子

渗透攻防实战:反向代理信任边界错误导致的 IP 白名单绕过验证与修复

精选回复

发布于

背景

在授权渗透测试中,后台接口经常同时依赖登录态和来源 IP 白名单。应用部署在 Nginx、Ingress 或云负载均衡之后时,开发人员通常从 X-Forwarded-For、X-Real-IP 获取客户端地址。如果代理链和可信代理范围配置错误,攻击者可自行注入请求头,将外部请求伪装成 127.0.0.1 或办公网地址,最终绕过应用层访问控制。

本文以一条典型链路为例:客户端到公网 Nginx,再到应用服务。测试目标是验证来源地址是否可伪造、确认信任边界、检查日志是否保留原始链路,并给出可直接落地的修复配置。所有操作应仅在明确授权的目标及测试窗口内进行。

问题定位

先确认限制来自哪一层。常见现象是普通请求返回 403,而增加来源地址头后响应发生变化。不要只依据状态码判定漏洞,还要对比响应长度、跳转位置、页面特征和服务端审计日志。

target='

# 基线请求
curl -sk -o /tmp/base.body -D /tmp/base.head 
  -w 'base status=%{http_code} size=%{size_download} redirect=%{redirect_url}\n' 
  "$target"

# 分别测试常见客户端地址头,不要一次加入多个头
for h in 
  'X-Forwarded-For: 127.0.0.1' 
  'X-Real-IP: 127.0.0.1' 
  'Forwarded: for=127.0.0.1'
do
  curl -sk -o /tmp/test.body -D /tmp/test.head 
    -w "$h status=%{http_code} size=%{size_download} redirect=%{redirect_url}\n" 
    -H "$h" "$target"
done

sha256sum /tmp/base.body /tmp/test.body

若基线为 403,加入单个 X-Forwarded-For 后变为 200,只能说明该头可能影响了决策。下一步要排除缓存、WAF 分支、认证跳转和偶发响应。建议重复测试,并使用一个明显不在白名单内的地址作为负对照,例如 198.51.100.10。

技术分析

X-Forwarded-For 通常是逗号分隔的地址链。代理会把直接客户端地址追加到已有值后面,但不同框架可能取最左、最右或第一个满足条件的地址。如果公网入口没有覆盖外部传入的头,而应用无条件取最左侧值,攻击者就能控制授权判断。

位置常见错误结果
公网 Nginx使用 $proxy_add_x_forwarded_for 保留外部伪造值下游看到攻击者提供的首地址
应用框架无条件 trust proxy 或信任全部网段req.ip 可由请求头控制
业务代码字符串前缀判断内网地址172.16.0.10.example 等异常值可能误判
日志系统只记录解析后的 client_ip难以还原直接连接来源

关键原则是:只有由受控代理接收的请求,才允许解析转发地址头;公网边界必须丢弃或覆盖客户端提交的同名头。应用还应基于明确的 CIDR 解析地址,而不是 startsWith 或正则片段匹配。

操作步骤

第一步,建立基线。记录请求时间、测试源 IP、请求 ID、状态码和响应摘要,避免后续无法与服务端日志对应。

第二步,测试单头影响。分别验证 X-Forwarded-For、X-Real-IP 和标准 Forwarded,不要同时设置,以便定位真正被消费的字段。

第三步,验证地址链解析规则。以下测试值可判断应用取最左还是最右,但不应尝试访问测试范围之外的接口。

# 正向与负向对照
curl -sk -H 'X-Forwarded-For: 127.0.0.1, 198.51.100.10' 
  -w '%{http_code} %{size_download}\n' 
  ' -o /tmp/a.body

curl -sk -H 'X-Forwarded-For: 198.51.100.10, 127.0.0.1' 
  -w '%{http_code} %{size_download}\n' 
  ' -o /tmp/b.body

cmp -s /tmp/a.body /tmp/b.body; echo "body_equal=$?"

第四步,从代理和应用日志双向核对。Nginx 的 $remote_addr 是直接 TCP 对端;$realip_remote_addr 可在 realip 模块改写地址后保留原始值。两者必须同时记录,否则一旦 client_ip 被伪造,审计链会失真。

log_format security escape=json
  '{"time":"$time_iso8601",'
  '"request_id":"$request_id",'
  '"peer_ip":"$realip_remote_addr",'
  '"client_ip":"$remote_addr",'
  '"xff":"$http_x_forwarded_for",'
  '"method":"$request_method",'
  '"uri":"$request_uri",'
  '"status":$status}';

access_log /var/log/nginx/security_access.log security;

第五步,检查实际配置而非只看模板。Nginx 可用 nginx -T 展开全部 include;Kubernetes Ingress 还要检查控制器 ConfigMap、入口 Service 的 externalTrafficPolicy,以及云负载均衡是否额外写入地址头。

nginx -T 2>&1 | grep -nE 'real_ip|set_real_ip_from|proxy_set_header|forwarded'

# Kubernetes 场景
kubectl -n ingress-nginx get configmap ingress-nginx-controller -o yaml
kubectl -n ingress-nginx get deploy ingress-nginx-controller -o yaml | 
  grep -nE 'use-forwarded-headers|enable-real-ip|proxy-real-ip-cidr'

安全配置示例

若架构只有一个受控负载均衡,Nginx 应仅信任该负载均衡所在 CIDR,并明确解析规则。下面的 10.20.0.0/24 只是示例,生产环境必须替换为真实、最小化的代理网段。

# 仅信任受控代理网段,禁止写成 0.0.0.0/0
set_real_ip_from 10.20.0.0/24;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

location / {
    # 传给应用的值由当前 Nginx 重新生成
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Request-ID $request_id;
    proxy_pass 
}

如果公网 Nginx 本身就是信任边界,覆盖 X-Forwarded-For 通常比追加更稳妥。若确实存在多级受控代理,则应逐跳列出代理网段,并通过测试确认递归解析方向。不要为了“兼容”而信任所有私网段,因为同一内网中的普通主机并不等于可信代理。

应用侧也要限制代理跳数或代理地址。例如 Express 不应直接使用 app.set('trust proxy', true),可改为固定跳数或受控网段,并使用成熟 IP 库执行 CIDR 判断。

const proxyaddr = require('proxy-addr');

const trustedProxy = proxyaddr.compile([
  'loopback',
  '10.20.0.0/24'
]);
app.set('trust proxy', trustedProxy);

// IP 白名单只作为附加控制,后台仍需强认证和权限校验

风险判定与证据

只有当伪造地址头能稳定改变权限结果,且请求确实来自非白名单测试源时,才应判定为访问控制绕过。报告中至少保留以下证据:

  • 基线请求与伪造头请求的完整时间、状态码、响应长度和关键响应差异。
  • 边界代理日志中的 peer_ip、client_ip、原始 X-Forwarded-For 和 request_id。
  • 触发问题的最小配置片段,以及真实代理拓扑和可信 CIDR。
  • 负对照结果,例如外部保留地址未获得权限、移除伪造头后恢复 403。
  • 受影响接口范围,以及是否还需要有效登录态、特定角色或二次认证。
验证应以最小影响为原则。优先使用健康检查、只读后台页面或专门测试接口,不执行数据修改、账号创建或敏感信息批量导出。

修复建议

  • 在最外层受控入口删除外部提交的 X-Forwarded-For、X-Real-IP、Forwarded,再按统一规则重建。
  • 仅信任明确的负载均衡和反向代理 CIDR,禁止 0.0.0.0/0、全部 RFC1918 网段或不受控容器网段。
  • 应用层按可信代理地址或固定跳数解析客户端 IP,统一 IPv4、IPv6 和 IPv4-mapped IPv6 的规范化逻辑。
  • 不要将来源 IP 作为唯一认证因素。后台接口应同时执行会话认证、角色授权,敏感操作增加二次确认。
  • 日志同时记录直接对端、解析后客户端地址、原始转发头、请求 ID 和认证主体,并控制日志访问权限。
  • 在 CI 或预发布环境加入回归用例:外部请求即使携带 127.0.0.1 或办公网地址,也必须保持 403。

总结

这类漏洞的核心不是某个请求头本身,而是代理链中的信任边界不清。有效的渗透验证需要完成三件事:用正负对照证明权限结果可被外部输入影响;结合代理与应用日志定位地址解析发生在哪一层;通过最小可信 CIDR、入口覆盖请求头、应用强认证和完整日志形成闭环。修复后应从公网入口、代理节点和应用直连路径分别回归,避免只改一层配置后仍可从旁路复现。

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

这类问题的关键不是“是否读取 X-Forwarded-For”,而是每一跳是否只信任自己的上游。验证时建议把直连后端和经过代理两条链路分开测,否则很容易把 CDN/WAF 的改写行为误判成应用漏洞。

先记录后端实际看到的来源信息。Nginx 可临时增加一组访问日志:

log_format iptrace '$remote_addr peer=$realip_remote_addr '
                   'xff="$http_x_forwarded_for" '
                   'xri="$http_x_real_ip" uri=$request_uri status=$status';
access_log /var/log/nginx/iptrace.log iptrace;

然后分别验证正常请求、伪造头以及绕过前置代理直连后端:

curl -i 
curl -i -H 'X-Forwarded-For: 127.0.0.1' 
curl -i -H 'X-Real-IP: 10.0.0.10' 
curl -i --resolve example.test:443:BACKEND_IP \
  -H 'X-Forwarded-For: 127.0.0.1' 

如果后两种请求能改变白名单判断,通常存在两个问题之一:后端对任意来源启用了 forwarded-header 信任,或者后端端口可被外部直接访问。修复应同时覆盖网络层和解析层,不能只在业务代码里调整取 IP 的顺序。

以 Nginx 为例,只声明实际反代节点的地址段,并开启递归解析;不要写成 0.0.0.0/0:

set_real_ip_from 10.20.0.0/16;   # 仅填写真实 LB/Ingress 网段
set_real_ip_from 192.0.2.15/32;  # 固定出口代理
real_ip_header X-Forwarded-For;
real_ip_recursive on;

location /admin/ {
    allow 10.30.0.0/16;
    deny all;
    proxy_pass 
}

最外层代理还应覆盖而不是透传客户端提交的来源头。若 Nginx 就是边界代理:

proxy_set_header X-Real-IP       $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header Forwarded       "";

多级代理场景不要在每层都无条件覆盖:边界层清洗客户端头,后续受信代理再用 $proxy_add_x_forwarded_for 追加。与此同时,用安全组或防火墙限制应用端口只能由 LB/Ingress 访问,例如:

iptables -A INPUT -p tcp --dport 8080 -s 10.20.0.0/16 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j DROP

最后建议把回归条件写明确:伪造 X-Forwarded-For、X-Real-IP、标准 Forwarded 以及重复请求头都不能改变鉴权结果;直连后端必须网络不可达;经过受信代理时,日志中的客户端地址与代理链顺序应符合预期。IP 白名单最好只作为附加限制,管理接口仍保留独立身份认证,避免代理配置再次变化后直接暴露权限。

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

最近浏览 0

  • 没有会员查看此页面。

SiteMap HACKHAT © 2026 All rights reserved.