发布于7小时前7小时 背景网站接入 CDN、WAF 或反向代理后,源站看到的连接地址通常是代理节点,而客户端真实 IP 由 X-Forwarded-For、X-Real-IP 等请求头传递。这里容易出现两个问题:一是源站无条件信任客户端可控请求头,导致访问控制、限流和审计被绕过;二是源站仍可被公网直接访问,使攻击者跳过 CDN 与 WAF。下面以一套经过授权的测试环境为例:公网流量先到 CDN,再转发至 Nginx,后端应用根据客户端 IP 实施管理接口限制。重点检查代理信任边界、源站暴露、日志留痕以及修复后的验证方法。所有探测和验证都应限定在自有系统或书面授权范围内。测试前应确认域名、源站地址、端口和时间窗口,避免影响第三方 CDN 节点。问题定位先画清请求链路,不要只检查应用代码。常见链路是“客户端—CDN/WAF—Nginx—应用”。需要分别确认连接层来源、代理传递的地址头,以及应用最终采用了哪个字段。检查点需要确认的内容常见风险CDN真实 IP 使用哪个请求头、节点出口网段不同厂商头名称不一致Nginxreal_ip_header 与 set_real_ip_from信任任意来源提交的地址头源站防火墙是否仅允许 CDN 回源网段公网可直接访问源站应用限流和鉴权读取 REMOTE_ADDR 还是自定义头直接读取 X-Forwarded-For日志是否同时记录连接地址、解析地址和转发链伪造后无法还原请求来源授权验证步骤第一步是在正常入口建立基线。使用测试域名请求一个无副作用的健康检查页面,同时保存响应头。部分 CDN 会返回节点标识或缓存命中信息,可辅助判断流量是否经过代理。curl -skD normal.headers -o /dev/null \ sed -n '1,30p' normal.headers第二步检查应用是否错误信任客户端传入的地址头。仅对测试接口发送一个保留地址作为标记,并在源站日志中核对最终解析结果。不要用管理员真实地址测试,避免误触发权限逻辑。curl -skD forged.headers -o /dev/null \ -H 'X-Forwarded-For: 192.0.2.123' \ -H 'X-Real-IP: 192.0.2.123' \ 192.0.2.123 识别为真实来源,说明某一层直接采用了客户端可控字段。不过仅凭响应差异还不能下结论,需要结合 Nginx 日志确认是 CDN 追加了地址链,还是源站覆盖规则配置错误。第三步验证源站是否能够被绕过。已知自有源站地址时,可以使用 curl 的 resolve 参数,将业务域名的 TLS SNI 与 Host 保持不变,但把连接定向到源站。这样比直接访问 IP 更接近真实回源请求。ORIGIN_IP='203.0.113.10' curl -skD origin.headers -o /dev/null \ --resolve \ sed -n '1,30p' origin.headers若源站直接返回正常业务页面,而边界防火墙也没有限制来源,则 CDN/WAF 只是一条可选路径。此时攻击流量可以直接到达源站,绕过边缘限速、Bot 管理和部分规则。技术分析:不要信任“请求头”,只信任“可信上一跳”X-Forwarded-For 本质上是普通 HTTP 请求头。安全的处理方式不是简单读取最左侧或最右侧地址,而是先确认当前 TCP 连接是否来自可信代理,再按照确定的代理层数解析地址链。下面这种配置风险较高,因为它允许任意来源通过 X-Forwarded-For 改写 Nginx 认定的客户端地址:set_real_ip_from 0.0.0.0/0; set_real_ip_from ::/0; real_ip_header X-Forwarded-For; real_ip_recursive on;较合理的做法是仅信任 CDN 官方公布且经过变更管理的回源网段。以下地址仅为文档示例,部署时必须替换成实际网段:# /etc/nginx/conf.d/realip.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_recursive 开启后,Nginx 会从地址链末端向前排除可信代理,最终选择第一个非可信地址。其前提是可信代理网段配置准确;如果把整个互联网加入信任列表,递归解析反而会放大伪造风险。日志留痕配置排查这类问题时,只记录 remote_addr 往往不够。启用 realip 模块后,remote_addr 可能已经被替换,因此应同时保留原始连接地址、解析后的客户端地址和完整转发链。log_format proxy_audit '$time_iso8601 request_id=$request_id ' 'peer=$realip_remote_addr client=$remote_addr ' 'xff="$http_x_forwarded_for" host="$host" ' 'request="$request" status=$status bytes=$body_bytes_sent ' 'rt=$request_time uaddr="$upstream_addr" ' 'urt="$upstream_response_time" ua="$http_user_agent"'; access_log /var/log/nginx/proxy_audit.log proxy_audit;其中 peer 表示与 Nginx 建立连接的上一跳,client 表示经过可信代理规则解析后的地址。正常情况下,peer 应落在 CDN 回源网段;如果 peer 是普通公网地址且请求仍获得业务响应,通常意味着源站访问控制未收紧。可以使用 awk 快速统计直接访问源站的连接来源。这里按日志中的 peer 字段提取,只用于初步聚类,正式调查应交叉核对防火墙、负载均衡和应用日志。awk '{ for (i=1; i<=NF; i++) { if ($i ~ /^peer=/) { sub(/^peer=/, "", $i) count[$i]++ } } } END { for (ip in count) print count[ip], ip }' /var/log/nginx/proxy_audit.log | sort -nr | head -30源站访问控制仅修正真实 IP 解析还不够。源站公网入口应在云安全组、主机防火墙或负载均衡访问控制层,仅放行 CDN 回源网段和必要的运维通道。应用层 allow 或 deny 可以作为补充,但不应替代网络层限制。下面是 nftables 的结构示例。实施前应通过带外控制台确认回滚能力,并先验证 CDN 当前出口网段,避免误封生产回源流量。table inet origin_filter { set cdn4 { type ipv4_addr flags interval elements = { 192.0.2.0/24 } } chain input { type filter hook input priority 0 policy drop ct state established,related accept iifname "lo" accept # 运维入口应替换为实际堡垒机网段 ip saddr 198.51.100.32/28 tcp dport 22 accept # 业务端口只允许 CDN 回源 ip saddr @cdn4 tcp dport { 80, 443 } accept } }如果 CDN 支持回源双向 TLS、固定回源证书、签名请求头或私有链路,建议同时启用。固定请求头只能作为附加校验:如果源站仍公开可达且该值泄露,它不能替代网络层访问控制。应用层权限边界客户端 IP 适合做风控信号和辅助限流,不适合单独承担管理接口鉴权。即使真实 IP 解析完全正确,办公出口、代理节点和 NAT 环境也会让多个用户共享地址。管理接口至少应使用独立身份认证、细粒度授权和操作审计。后端还应避免直接读取任意 X-Forwarded-For。更稳妥的方式是让 Nginx 完成可信代理解析,再把规范化后的地址传给应用,并覆盖外部同名头:location / { proxy_set_header Host $host; proxy_set_header X-Client-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Request-ID $request_id; proxy_pass }应用只消费网关写入的 X-Client-IP,同时确保应用端口不对公网或非受控内网开放。否则攻击者可以绕过 Nginx,直接连接应用并自行构造该请求头。修复后的复测从正常域名访问,确认 CDN 回源成功,业务状态码和证书链正常。重复提交伪造 X-Forwarded-For,确认日志中的 client 不会被任意值覆盖。使用 resolve 直连源站,预期连接超时、被拒绝,或由独立默认站点返回固定拒绝响应。检查 peer 是否始终属于受信 CDN 网段,并对异常来源设置告警。确认应用限流、审计和管理接口读取的是规范化地址,而不是原始客户端请求头。模拟 CDN 网段更新流程,验证配置拉取、语法检查、灰度发布和回滚机制。Nginx 配置发布前至少执行语法检查,并保留当前可用版本:nginx -T > /var/backups/nginx-config-$(date +%F-%H%M%S).txt nginx -t && systemctl reload nginx # 发布后抽查审计日志 tail -n 50 /var/log/nginx/proxy_audit.log风险与修复优先级问题影响建议优先级源站公网可直连绕过 WAF、限速与边缘访问控制高信任任意 X-Forwarded-For伪造审计来源、绕过基于 IP 的策略高应用端口可被直接访问绕过网关头部覆盖和统一鉴权高日志只记录解析后地址事件发生后无法还原真实连接链路中CDN 网段依靠人工维护网段变化导致中断或信任范围陈旧中总结网站加速链路的关键不是“有没有 CDN”,而是每一层是否建立了明确的信任边界。源站只接受可信代理连接,Nginx 只解析可信上一跳提供的地址链,应用只使用网关规范化后的字段,同时保留原始连接地址与转发链日志。完成这些配置后,再通过正常入口、伪造请求头和源站直连三组测试复核,通常能够把真实 IP 伪造、WAF 绕过和日志失真这几类问题一起收敛。 网络请求、日志与边界流量分析示意 服务器、云资产与权限边界梳理示意
5小时前5小时 这类问题建议拆成三层处理:入口是否只能来自 CDN、转发头是否可信、应用与日志是否使用同一套客户端地址。 关键点不是“读取哪个 Header”,而是“只有 CDN 回源连接才有资格提供这个 Header”。如果源站仍可被公网直连,攻击者直接请求源站并伪造 X-Forwarded-For,限速、审计和封禁都会失真。 Nginx 可以按 CDN 官方公布的回源网段建立信任边界。假设 CDN 使用 X-Forwarded-For: set_real_ip_from 203.0.113.0/24; set_real_ip_from 2001:db8:1234::/48; real_ip_header X-Forwarded-For; real_ip_recursive on; log_format edge '$time_iso8601 ' 'client=$remote_addr ' 'peer=$realip_remote_addr ' 'xff="$http_x_forwarded_for" ' 'host="$host" request="$request" ' 'status=$status bytes=$body_bytes_sent ' 'request_id="$http_x_request_id"'; access_log /var/log/nginx/access.log edge; $remote_addr 是解析后的客户端地址,$realip_remote_addr 保留实际建立 TCP 连接的 CDN 节点地址。排障时两者都要记录,否则配置错误后很难还原。CDN 如果提供专用单值头,应优先使用其专用头,并确认该头会在边缘覆盖,而不是透传客户端同名字段。 源站侧最好直接做网络层收口,只允许 CDN 网段访问 80/443,运维入口另走固定地址或 VPN。例如使用 nftables: table inet filter { set cdn4 { type ipv4_addr flags interval elements = { 203.0.113.0/24 } } chain input { type filter hook input priority 0; ct state established,related accept iif "lo" accept ip saddr @cdn4 tcp dport { 80, 443 } accept tcp dport { 80, 443 } drop } } 还要检查常见的源站暴露路径:历史 DNS 记录、邮件头中的同机 IP、证书透明度记录、旧子域名、默认虚拟主机,以及同一 IP 上返回站点内容的其他端口。仅靠隐藏 DNS 不算防护。默认虚拟主机可以直接拒绝未知 Host,源站站点还可校验 CDN 回源携带的随机密钥头;不过密钥头只能作为补充,不能替代防火墙。 server { listen 443 ssl default_server; server_name _; return 444; } server { listen 443 ssl; server_name if ($http_x_origin_verify != "一段足够长的随机值") { return 403; } # proxy_pass / fastcgi_pass ... } 上线后建议做两组验证:一是直连源站并伪造转发头,确认被网络层或回源校验拒绝;二是经 CDN 请求,确认应用、访问日志和限速模块看到的地址一致。 # 直连源站测试,预期超时、拒绝或 403 curl -vk --resolve \ -H 'X-Forwarded-For: 1.2.3.4' \ # 经 CDN 测试 curl -sS -D- -o /dev/null # 检查配置与日志字段 nginx -T | grep -E 'set_real_ip_from|real_ip_header|real_ip_recursive|log_format' tail -f /var/log/nginx/access.log 最后别手工长期维护 CDN 网段。应定时从官方地址拉取、校验格式,生成配置后先执行 nginx -t,成功再 reload;防火墙地址集也要同步更新。更新失败时保留上一版,避免一次空列表把源站全部开放或全部阻断。
创建帐户或登录后发表意见