发布于4小时前4小时 背景:加速生效了,源站却仍能被直接访问网站接入 CDN 后,常见的遗漏不是缓存规则,而是源站边界:业务域名已经走加速节点,源站公网 443 端口却仍对所有地址开放。知道源站地址的人可以携带正确的域名直接访问,绕过部署在 CDN 上的限速、访问控制或 WAF。另一个容易同时出现的问题是:为了恢复访客 IP,Nginx 无条件信任 X-Forwarded-For,导致攻击者自行填写的地址进入访问日志,甚至影响基于 IP 的后台访问控制。下面以“CDN → Nginx → 本机应用”为例,只讨论自有或明确授权的网站环境,目标是验证加速入口、源站权限边界和日志是否一致。一、先确定三种地址各自代表什么连接对端地址:直接与源站建立 TCP 连接的地址,正常情况下应该是 CDN 回源节点。访客地址:由可信 CDN 通过约定请求头传递,经过 realip 模块校验后使用。原始请求头:客户端可能参与构造的数据,不能直接作为身份或访问权限依据。Nginx 启用 realip 模块后,$remote_addr 可能变成解析出的访客地址;$realip_remote_addr 则保留替换前的连接对端。限制“谁能连接源站”时,应检查后者,不能把访客地址误当成回源节点地址。二、问题定位:用四组请求区分边界准备一个由自己控制、不缓存的健康检查路径,例如 /__origin_probe,仅返回 204 或固定文本,不输出环境变量、版本信息和内部地址。测试时同时观察 CDN 日志与源站日志,避免把缓存命中误认为源站已收到请求。# 1. 正常通过 CDN 访问 curl -sS -D - -o /dev/null # 2. 指定连接源站,但保留正确的 Host 与 TLS SNI curl -sS -D - -o /dev/null \ --resolve site.example:443:203.0.113.20 \ # 3. 直连源站,同时伪造转发地址 curl -sS -D - -o /dev/null \ --resolve site.example:443:203.0.113.20 \ -H 'X-Forwarded-For: 198.51.100.77' \ # 4. 通过 CDN 携带相同的伪造头,检查边缘如何处理 curl -sS -D - -o /dev/null \ -H 'X-Forwarded-For: 198.51.100.77' \ IP 均为文档示例,执行前替换为授权目标。不要为了让测试“通过”而加 -k 忽略证书校验;TLS 配置错误也应单独记录。预期结果:正常 CDN 请求成功;直连源站被网络层拒绝,或被 Nginx 返回 403;伪造请求头不能改变这一结果。第四组需要核对日志:记录的访客地址应是实际测试出口,而不是手工填写的地址。三、Nginx 配置:分开处理访客 IP 与回源权限以下片段放在 http 上下文及对应业务 server 中。示例网段不代表任何实际 CDN,必须替换为服务商公布且适用于该产品的回源网段;IPv4、IPv6 都要覆盖。# http 上下文:只信任明确的代理网段 set_real_ip_from 192.0.2.0/24; real_ip_header X-Forwarded-For; real_ip_recursive on; # 使用原始连接对端判断是否来自允许的回源节点 geo $realip_remote_addr $allowed_origin_peer { default 0; 192.0.2.0/24 1; } log_format origin_audit escape=json '{"time":"$time_iso8601",' '"request_id":"$request_id",' '"peer":"$realip_remote_addr",' '"client":"$remote_addr",' '"xff":"$http_x_forwarded_for",' '"host":"$host",' '"method":"$request_method",' '"uri":"$uri",' '"status":$status,' '"upstream_status":"$upstream_status"}'; server { listen 443 ssl; server_name site.example; ssl_certificate /etc/nginx/tls/site.example/fullchain.pem; ssl_certificate_key /etc/nginx/tls/site.example/privkey.pem; access_log /var/log/nginx/origin_audit.log origin_audit; # 此处仅使用 if + return,不做复杂重写 if ($allowed_origin_peer = 0) { return 403; } location = /__origin_probe { return 204; } location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; # 单入口架构下向应用传递已校验的地址,不继续拼接原始头 proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; proxy_pass } }real_ip_recursive on 会按可信代理关系解析地址链,但它不是请求头真实性校验器。必须确认 CDN 会覆盖用户提交的同名头,或在地址链末端追加实际连接者地址;如果服务商提供专用的单值访客 IP 头,应按其官方约定调整。不要直接照搬另一家 CDN 的头名称和解析规则。这份配置适用于 CDN 直接连接 Nginx 的拓扑。如果中间还有负载均衡器,源站看到的连接对端可能是内网 LB。此时要重新设计各跳的可信关系,不能简单把整个内网都加入信任列表。四、上线顺序与日志验收# 确认构建包含 realip 模块 nginx -V 2>&1 | grep -- --with-http_realip_module # 检查最终配置;输出可能包含敏感配置,不要直接贴到公开论坛 sudo nginx -T # 语法校验通过后平滑重载 sudo nginx -t && sudo systemctl reload nginx # 确认应用未直接暴露到公网 sudo ss -lntp | grep ':8080' # 检查探测请求在源站的记录 sudo tail -n 100 /var/log/nginx/origin_audit.log应用监听地址应为 127.0.0.1:8080、受限的内网地址或 Unix socket,而不是无意开放的 0.0.0.0:8080。使用容器时还要核对端口发布规则,不能只检查容器内部监听。正常回源:peer 属于 CDN 网段,client 是真实测试出口,状态码为 204。普通直连:peer 是测试出口,client 不因伪造头改变,状态码为 403。网络层已拦截:直连没有 Nginx 日志是合理现象,应结合安全组或防火墙计数验证。应用请求:用 Nginx 生成的 request_id 关联应用日志,不把客户端自行提交的追踪标识直接当成可信审计标识。示例日志使用 $uri,避免默认记录查询参数中的令牌,但 URL 路径和请求头本身仍可能包含敏感数据。原始 XFF 建议只在排查期按需保留,并设置日志权限、轮转与保留期限。五、风险与修复建议set_real_ip_from 0.0.0.0/0 等于让任意来源声明访客地址,应删除;IPv6 的全网信任同理。优先在安全组或防火墙限制回源来源,Nginx 校验作为补充。只做 HTTP 拒绝仍会消耗 TLS 握手和连接资源。CDN 网段是共享基础设施,不是某个站点的独有身份。对更严格的源站保护,应使用服务商支持的、绑定本账户或本服务的回源 mTLS,或受认证保护的私有回源通道。回源网段更新应经过格式校验、差异审查、配置测试和回滚准备,不要把下载结果未经校验直接加载进生产配置。Host 限制和默认虚拟主机只能处理错误域名请求,不能阻止携带正确 Host、SNI 的直连。管理后台仍应使用独立认证、MFA 或受控管理网络。真实 IP 解析正确,并不意味着可以只靠 IP 完成高权限认证。总结网站接入加速服务后,验收不能只看域名是否解析到 CDN。还要分别验证:源站是否拒绝非授权连接、访客地址是否来自可信解析链、应用是否存在旁路端口,以及日志能否区分连接对端与最终访客。把这几项写进上线检查表,比事后仅凭一条 X-Forwarded-For 追查可靠得多。 网络请求、日志与边界流量分析示意 服务器、云资产与权限边界梳理示意
4小时前4小时 建议把“源站边界”和“真实 IP”分开验证,前者看 TCP 对端是否只能来自 CDN,后者看 Nginx 是否只信任这些对端提供的头。 1. 先从 CDN 外部节点直连源站 不要只用源站 IP 访问,HTTPS 下还要带正确的 Host 和 SNI: curl -vk --connect-timeout 5 \ --resolve \ ' 正确结果应是超时、拒绝连接或被防火墙丢弃,而不是返回站点内容。IPv4、IPv6 都要测,很多场景只封了 A 记录对应地址,AAAA 仍能直连。 源站限制最好放在安全组或主机防火墙,只允许 CDN 官方出口网段访问 80/443。不要单纯依赖 Nginx 的 allow/deny,因为启用 realip 后 $remote_addr 已经可能被改写成访客 IP,容易误判。证书签发、监控探针、回源健康检查等例外地址需要单独列入白名单。 2. Nginx 只信任 CDN 网段,不要全局信任请求头 以 CDN 提供 X-Forwarded-For 为例: 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 edge '$time_iso8601 client=$remote_addr ' 'peer=$realip_remote_addr ' 'xff="$http_x_forwarded_for" ' 'host="$host" request="$request" status=$status'; access_log /var/log/nginx/access.log edge; } 这里: $remote_addr 是 realip 模块处理后的访客地址; $realip_remote_addr 是实际与 Nginx 建立连接的对端,正常应落在 CDN 网段; set_real_ip_from 0.0.0.0/0 或信任整个内网大网段都不合适,否则客户端可伪造头部。 如果厂商提供的是经过清洗的专用头,例如 CF-Connecting-IP,优先按厂商文档使用该头: real_ip_header CF-Connecting-IP; 如果 CDN 使用 PROXY Protocol,则应配置为: listen 443 ssl proxy_protocol; real_ip_header proxy_protocol; 这两种模式不要凭猜测混用;CDN 未发送 PROXY Protocol 时开启它,会导致正常回源直接失败。 3. 做一次伪造头验证 curl -sS \ -H 'X-Forwarded-For: 1.2.3.4' \ ' 随后检查日志: tail -n 20 /var/log/nginx/access.log nginx -T | grep -E 'set_real_ip_from|real_ip_header|real_ip_recursive' 日志中的 client 不应变成伪造的 1.2.3.4;peer 应是 CDN 回源地址。如果前面还有 SLB、Ingress 或本地反向代理,需要把完整代理链梳理清楚,并确保每一跳都覆盖/追加头部且只信任上一跳。 最后建议持续监控 $realip_remote_addr:一旦出现非 CDN 网段,通常意味着防火墙漏放、IPv6 未限制,或者存在另一条可直达源站的入口。
创建帐户或登录后发表意见