跳转到帖子

咖啡馆实战:CDN 加速站点的源站暴露与真实客户端 IP 信任边界排查

精选回复

发布于

背景

网站接入 CDN、WAF 或反向代理后,常见链路是“客户端 → CDN/WAF → Nginx → 应用”。这类架构既承担加速,也改变了客户端 IP 的获取方式。如果源站仍可被公网直连,或 Nginx、应用无条件信任 X-Forwarded-For,就可能出现后台 IP 白名单绕过、限速失效、审计日志失真等问题。

下面以已获授权的测试环境为例,排查两个具体问题:源站是否只能由 CDN 回源节点访问,以及业务使用的客户端 IP 是否来自可信代理链。

问题定位

测试前先向运维确认域名、源站测试地址、CDN 回源网段和允许的测试时间,不要通过扫描第三方网段猜测源站。假设测试信息如下:

  • 业务域名:demo.example.com
  • 测试源站:203.0.113.10
  • 管理入口:/admin
  • 预期策略:源站 443 端口只允许 CDN 节点访问,管理入口不能单独依赖客户端 IP 完成认证

重点检查以下现象:

  • 使用源站 IP 配合正确 Host 或 SNI,可以绕过 CDN 直接访问业务。
  • 修改 X-Forwarded-For 后,/admin 的状态码、页面长度或跳转位置发生变化。
  • 访问日志只记录伪造后的地址,无法还原实际 TCP 对端。
  • 限速、地域判断和后台白名单读取了未经规范化的请求头。

授权环境下的验证步骤

先记录通过 CDN 正常访问时的基线响应,再添加伪造请求头。这里只比较状态码和响应头,避免对业务执行修改操作。

# 1. 通过 CDN 获取基线
curl -skI 

# 2. 注入常见的本地或内网地址,观察响应是否变化
curl -skI  \
  -H 'X-Forwarded-For: 127.0.0.1'

curl -skI  \
  -H 'X-Forwarded-For: 10.10.10.10'

# 3. 已知且已获授权的源站地址,保留域名对应的 TLS SNI
curl -skI --resolve demo.example.com:443:203.0.113.10 \
  

# 4. 输出便于比较的关键字段
curl -sk -o /dev/null \
  -w 'code=%{http_code} size=%{size_download} redirect=%{redirect_url}\n' \
   \
  -H 'X-Forwarded-For: 127.0.0.1'

如果第三项能够直接返回正常业务页面,说明“隐藏源站”只停留在 DNS 层,未形成网络访问控制。如果第二项使原本的 401 或 403 变为 200,通常说明代理头参与了权限判断,并且信任边界配置不正确。

验证时应使用只读请求和专用测试账号。发现权限变化后即可停止,不需要继续进入后台或读取业务数据。

技术分析:X-Forwarded-For 不能直接视为客户端地址

X-Forwarded-For 是普通 HTTP 请求头,客户端可以主动提交。可信代理通常会在转发时追加地址,因此它可能形成一个地址链。安全处理的前提不是“取第一个”或“取最后一个”,而是明确哪些 TCP 对端属于可信代理,再从右向左剥离可信节点。

常见错误配置如下:

# 错误示例:等于信任任意来源提交的代理头
set_real_ip_from 0.0.0.0/0;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

另一类问题出现在应用层。例如直接读取 X-Forwarded-For 的第一个值,再用于后台白名单:

# 风险逻辑示意
client_ip = request.headers.get('X-Forwarded-For', request.remote_addr).split(',')[0]
if client_ip in admin_allowlist:
    allow_admin()

即使 Nginx 配置正确,应用再次解析原始请求头,也会绕过 Nginx 已完成的地址规范化。应用应读取反向代理传递的、经过信任链计算后的连接地址,并且后台认证不能只依赖 IP。

Nginx 排查与日志留痕

先查看实际加载的完整配置,避免只检查某个配置文件而遗漏 include 内容。

sudo nginx -T 2>&1 | grep -nE \
  'set_real_ip_from|real_ip_header|real_ip_recursive|proxy_set_header|log_format|allow|deny|limit_req_zone'

# 检查 Nginx 是否编译或动态加载 realip 模块
nginx -V 2>&1 | grep -o 'http_realip_module'

建议同时记录规范化后的客户端地址、实际 TCP 对端和原始代理头。这样既能判断配置结果,也能发现绕过 CDN 的直连请求。

log_format proxy_audit escape=json
  '{"time":"$time_iso8601",'
  '"client":"$remote_addr",'
  '"peer":"$realip_remote_addr",'
  '"xff":"$http_x_forwarded_for",'
  '"host":"$host",'
  '"request":"$request",'
  '"status":$status,'
  '"request_id":"$request_id"}';

access_log /var/log/nginx/proxy_audit.log proxy_audit;

其中 remote_addr 是 Real IP 模块处理后的客户端地址,realip_remote_addr 保留原始连接地址。若 peer 不是 CDN 网段却能获得正常业务响应,应优先检查源站防火墙和旁路入口。

# 查看最近请求,按实际环境安装 jq 或直接读取原始日志
sudo tail -n 200 /var/log/nginx/proxy_audit.log | jq -c \
  '{time,client,peer,xff,host,status,request_id}'

# 统计直接连接源站的对端地址
sudo jq -r '.peer' /var/log/nginx/proxy_audit.log \
  | sort | uniq -c | sort -nr | head

正确配置可信代理边界

set_real_ip_from 只能填写当前实际使用的 CDN 或负载均衡节点网段,不能使用全网段。下面的地址仅为文档示例,部署时应替换为厂商正式发布并定期同步的回源网段。

# /etc/nginx/conf.d/trusted-proxy.conf
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;

# 限速应在 Real IP 处理后使用规范化地址
limit_req_zone $binary_remote_addr zone=per_client:10m rate=10r/s;

server {
    listen 443 ssl default_server;
    server_name _;
    return 444;
}

server {
    listen 443 ssl;
    server_name demo.example.com;

    location / {
        limit_req zone=per_client burst=20 nodelay;
        proxy_set_header Host $host;
        proxy_set_header X-Request-ID $request_id;
        proxy_pass 
    }
}

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

sudo nginx -t && sudo systemctl reload nginx
sudo systemctl status nginx --no-pager
sudo tail -n 50 /var/log/nginx/error.log

如果链路中还有云负载均衡、Ingress 或服务网格,需要把每一跳都画出来,并分别确认请求头是覆盖、追加还是原样透传。不能机械复制其他环境的 trusted proxy 配置。

源站访问控制

Nginx 的 Host 校验只能减少错误路由,不能替代网络层限制。更可靠的做法是在云安全组、防火墙或上游 ACL 中,仅允许 CDN 回源网段访问源站的 80、443 端口。运维管理流量应通过 VPN、堡垒机或独立管理网进入。

实施限制前,需要单独梳理健康检查、证书验证、监控探针和灾备节点,避免误封正常链路。CDN 网段发生变化时,应通过受控任务更新规则,并保留变更记录和失败回滚。

风险判断与修复优先级

发现主要影响修复优先级
源站可公网直连绕过 CDN/WAF、流量防护和边缘访问策略高
信任 0.0.0.0/0 的代理头客户端 IP 可伪造,影响白名单、限速和审计高
应用直接解析 X-Forwarded-For代理层规范化失效,多组件判断不一致高
日志只记录处理后的地址难以区分 CDN 回源与源站直连中
后台仅依赖 IP 白名单代理误配或办公网失陷后缺少第二道认证高

修复顺序建议是:先限制源站入口,再收紧可信代理网段,然后统一应用取 IP 的方式,最后补齐日志告警。后台入口应保留账号认证、多因素认证和最小权限控制,IP 白名单只作为附加条件。

回归验证

  • 通过 CDN 正常访问,日志中的 peer 属于 CDN 网段,client 为测试终端出口地址。
  • 客户端自带 X-Forwarded-For 不会改变后台授权结果。
  • 从非 CDN 网络直连源站时,由安全组丢弃或明确拒绝连接。
  • 未知 Host 命中默认虚拟主机,不返回真实业务内容。
  • 限速键使用规范化后的客户端地址,不会把全部用户聚合到 CDN 节点地址。
  • 日志平台可同时检索 client、peer、xff 和 request_id,并对异常 peer 触发告警。

总结

CDN 加速并不天然等于源站隐藏。真正有效的边界由源站网络 ACL、可信代理网段、Real IP 处理、应用认证和可追溯日志共同组成。排查时不要只看页面是否经过 CDN,而要验证“谁可以连接源站”“哪个组件有权声明客户端 IP”“权限判断最终使用了哪个地址”。这三个问题确认清楚,才能避免加速链路反过来成为权限绕过和审计失真的入口。

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

这类问题建议分开验证“源站是否能被绕过”和“源站是否会信任伪造的客户端 IP”。先用实际源站 IP 保持域名和 TLS SNI 不变,检查能否直连:

curl -sS -D- --resolve  \
   -o /dev/null

把示例 IP 换成自有源站地址;若直连能返回正常业务内容,即使 DNS 已指向 CDN,也仍存在绕过入口。核对历史 DNS、遗留 A/AAAA 记录和暴露在其他服务配置中的源站地址后,优先在安全组或主机防火墙上限制源站仅接受 CDN 回源网段;管理和健康检查流量单独放行。默认虚拟主机也应拒绝未知 Host,避免直连时落到业务站点。

客户端 IP 则要在源站只信任 CDN 网段提供的头,不能仅凭请求里出现 X-Forwarded-For 就认定可信。以 Nginx 和 CDN 的官方回源网段为例:

# 将网段替换为 CDN 官方公布并定期更新的回源地址
set_real_ip_from 192.0.2.0/24;
real_ip_header CF-Connecting-IP;
real_ip_recursive on;

log_format edge '$remote_addr peer=$realip_remote_addr '
                '"$request" status=$status';

如果用的是 X-Forwarded-For,要确认 CDN 如何追加或覆盖该头,并只把可信代理网段纳入解析链。最后从 CDN 正常访问时发送一个自造的转发头做验证,确认边缘会覆盖或安全处理它;同时检查日志里的客户端地址和直接连接对端地址是否符合预期。

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

最近浏览 0

  • 没有会员查看此页面。