跳转到帖子

咖啡馆实战:网站接入 CDN 与反向代理后的真实 IP、访问控制和日志留痕

精选回复

发布于

背景

网站接入 CDN、WAF 或 Nginx 反向代理后,源站看到的连接地址通常是代理节点 IP。为了恢复访客地址,常见做法是读取 X-Forwarded-For、X-Real-IP 或厂商提供的请求头。如果源站无条件信任这些字段,攻击者就可能伪造来源地址,绕过后台 IP 白名单、限速策略或审计规则。

下面以一套经过授权的测试环境为例:公网 CDN 转发到 Nginx 源站,Nginx 再代理到应用服务。重点验证三个问题:源站是否可以被直接访问、客户端地址是否可伪造、边缘与源站日志能否形成完整证据链。

测试仅应在自有系统或明确授权范围内进行。验证白名单时使用专门测试账号和测试接口,避免影响真实管理端。

问题定位

先画清实际链路,不要只看域名解析结果。需要确认客户端、CDN、源站 Nginx、应用四个位置分别记录了什么地址,以及哪个组件负责访问控制。

  • 域名是否始终解析到 CDN,源站地址是否通过历史 DNS、证书透明度日志、邮件回源记录或错误页泄露。
  • 源站安全组是否只允许 CDN 回源网段,还是对整个互联网开放 80、443 端口。
  • Nginx 是否配置 real_ip_header,但遗漏 set_real_ip_from,或错误信任 0.0.0.0/0。
  • 应用是否直接使用 X-Forwarded-For 的第一个值进行白名单判断。
  • 边缘日志、Nginx access log 和应用审计日志是否使用统一请求标识。

授权验证步骤

第一步是在正常域名入口发送带有伪造头的请求,记录状态码和响应中的请求标识。第二步从已批准的测试出口直接访问源站地址,并通过 Host 和 TLS SNI 还原虚拟主机。第三步对比不带伪造头与带伪造头时,源站日志中的 remote_addr、realip_remote_addr 和 forwarded_for。

# 1. 经 CDN 访问测试接口
curl -sk -D-  \
  -H 'X-Forwarded-For: 127.0.0.1' \
  -H 'X-Real-IP: 127.0.0.1'

# 2. 在授权环境中绕过 DNS,直接连接已知源站
# --resolve 同时保留 Host 与 TLS SNI,比直接访问 IP 更接近真实回源请求
curl -skv --resolve  \
   \
  -H 'X-Forwarded-For: 10.10.10.15'

# 3. 查看 Nginx 最终加载的 real_ip 与日志配置
sudo nginx -T 2>&1 | grep -nE 'real_ip|set_real_ip_from|log_format|access_log'

# 4. 按时间和请求标识检索源站日志
sudo grep 'req-test-20250308-001' /var/log/nginx/access.log

如果正常请求返回 403,而添加 X-Forwarded-For: 127.0.0.1 后返回 200,不能立即认定为应用漏洞。还要确认该请求是否能够从非可信代理直接到达源站。如果源站网络层已严格限制为 CDN 回源网段,外部利用条件会明显降低;但内部旁路、错误安全组和新增加速节点仍可能扩大风险。

技术分析:不要混淆三类地址

  • remote_addr:当前与 Nginx 建立 TCP 连接的对端地址。启用 realip 模块后,它可能被改写。
  • realip_remote_addr:启用 realip 模块后保留的原始连接地址,适合确认请求是否真的来自可信代理。
  • http_x_forwarded_for:原始请求头,可能包含多级代理地址,也可能完全由客户端构造,不能单独作为安全依据。

典型错误是将任意来源提交的 X-Forwarded-For 直接覆盖 remote_addr,再使用 remote_addr 判断后台白名单。另一个常见错误是应用取逗号分隔列表的最左值,却没有先验证最右侧代理链是否属于受信任网段。

Nginx 修正配置

可信代理范围应来自当前 CDN 厂商发布并经过变更管理的回源地址段,不要使用 0.0.0.0/0。以下地址仅为文档示例,部署时必须替换。

http {
    # 仅信任实际 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;

    # 同时记录原始连接、解析后地址和完整转发链
    log_format security_json escape=json
      '{"time":"$time_iso8601",'
      '"request_id":"$request_id",'
      '"peer_ip":"$realip_remote_addr",'
      '"client_ip":"$remote_addr",'
      '"xff":"$http_x_forwarded_for",'
      '"host":"$host",'
      '"request":"$request",'
      '"status":$status,'
      '"bytes":$body_bytes_sent,'
      '"referer":"$http_referer",'
      '"ua":"$http_user_agent",'
      '"upstream":"$upstream_addr",'
      '"upstream_status":"$upstream_status",'
      '"request_time":$request_time}';

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

    server {
        listen 443 ssl;
        server_name 

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

修改后先执行 sudo nginx -t,再使用 sudo nginx -s reload 平滑加载。随后重复前述请求,确认伪造地址只作为未受信任输入留在日志中,不能改变访问控制结果。

源站边界加固

请求头校验不能替代网络隔离。更稳妥的做法是在云安全组或主机防火墙中,只允许 CDN 回源地址访问源站端口;运维入口单独走 VPN、堡垒机或零信任接入。源站还应验证回源身份,例如双向 TLS、厂商回源鉴权头或独立回源域名。

# nftables 示例:默认拒绝公网直接访问源站 HTTPS
# 执行前应核对管理链路,并在控制台保留回滚通道
sudo nft add table inet origin_filter
sudo nft 'add chain inet origin_filter input { type filter hook input priority 0; policy accept; }'
sudo nft add rule inet origin_filter input tcp dport 443 ip saddr 192.0.2.0/24 accept
sudo nft add rule inet origin_filter input tcp dport 443 ip6 saddr 2001:db8:100::/48 accept
sudo nft add rule inet origin_filter input tcp dport 443 drop

# 查看规则及命中计数
sudo nft -a list table inet origin_filter

生产环境不建议直接复制执行防火墙命令。应先将规则写入基础设施代码,在测试实例验证,再分批上线,并考虑 CDN 地址段更新、健康检查和故障切换节点。

日志留痕与排查方法

边缘、源站和应用日志至少保留统一的 request_id、时间、原始连接地址、解析后的客户端地址、Host、URI、状态码和上游状态。若应用已有 trace ID,优先沿用;否则由最外层可信代理生成,并覆盖客户端传入的同名字段,避免请求标识碰撞。

可重点检索以下异常:

  • peer_ip 不属于 CDN 网段,但请求成功进入业务虚拟主机,说明源站可能存在旁路。
  • xff 包含 127.0.0.1、私网地址或异常长代理链,并伴随后台接口 200 响应。
  • 同一 request_id 在边缘日志中不存在,却出现在源站日志,可能是直接访问源站。
  • 短时间内 client_ip 大量变化,但 peer_ip、User-Agent 和会话标识相同,可能存在伪造地址绕过限速。
  • CDN 已拦截的请求在应用日志中仍有成功记录,需要检查备用域名、IPv6 或未纳管端口。

风险分级与修复建议

  • 高风险:源站公网可达,伪造请求头可直接绕过管理后台白名单或高权限操作限制。应立即封闭源站入口,并将权限控制迁移到强身份认证。
  • 中风险:源站仅允许 CDN 回源,但可信网段配置过宽、更新机制不明确,或内部网络可直达。应收敛网段并增加回源身份校验。
  • 低风险:伪造字段只影响日志展示,不改变鉴权、限速和审计结论。仍应修正,避免事件响应时误判来源。

IP 白名单只能作为附加边界,不应承担后台认证。管理端至少需要独立身份认证、最小权限、短会话、敏感操作二次确认和完整审计。对登录、找回密码、短信发送等接口,限速键应综合账号、会话、可信客户端地址和设备特征,不能只依赖一个可变请求头。

总结

网站接入 CDN 或加速器后,真正需要验证的不是页面是否能打开,而是代理信任链是否闭合:谁可以连接源站、谁有权声明客户端地址、哪个组件执行访问控制、日志能否还原完整路径。实测时同时保留正常入口、源站直连和伪造请求头三组结果,再结合网络边界与日志证据判断风险,通常比单看某个响应状态码更可靠。

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

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

最近浏览 0

  • 没有会员查看此页面。