发布于22小时前22小时 背景网站接入 CDN、WAF 或自建反向代理后,常见架构是“客户端 → 加速节点 → Nginx → 应用”。这类架构最容易被忽略的不是某个具体漏洞,而是代理信任边界:源站错误信任客户端提交的 X-Forwarded-For,应用又依据客户端 IP 放行后台、调试接口或内部 API。在一次授权测试中,某管理接口只允许 127.0.0.1 和办公网访问。正常外部请求返回 403,但向公开源站发送带有 X-Forwarded-For: 127.0.0.1 的请求后变成 200。问题并不在业务鉴权代码,而是 Nginx 将任意来源提供的请求头改写成了真实客户端地址。以下操作仅适用于自有或明确授权的站点。示例使用 portal.test 和 RFC 5737 文档地址 203.0.113.10,不对应真实目标。问题定位先确认请求实际经过哪些节点,并分别记录边缘入口和源站的响应。不要只看页面内容,应同时比较状态码、响应头、证书和日志中的连接来源。curl -skI # 已知并获准测试源站时,绕过 DNS 直接连接源站 curl -skI --resolve portal.test:443:203.0.113.10 \ # 验证源站是否错误采信客户端提交的转发头 curl -skI --resolve portal.test:443:203.0.113.10 \ -H 'X-Forwarded-For: 127.0.0.1' \ 403,而第三个请求变为 200、302 或返回内容长度明显变化,应继续检查 realip 配置以及应用使用的 IP 变量。测试时不需要执行新增账号、上传文件等有状态操作,仅验证访问控制差异即可。技术分析Nginx 的 ngx_http_realip_module 会按照 real_ip_header 读取地址,并在连接来源命中 set_real_ip_from 时改写 remote_addr。危险配置通常如下:# 错误示例:所有来源都被视为可信代理 set_real_ip_from 0.0.0.0/0; set_real_ip_from ::/0; real_ip_header X-Forwarded-For; real_ip_recursive on; location /admin/ { allow 127.0.0.1; allow 10.20.0.0/16; deny all; proxy_pass }此时任意直连源站的客户端都可以构造 X-Forwarded-For。由于访问控制阶段看到的是被改写后的 remote_addr,allow/deny 规则会把外部请求误判为本机或办公网请求。real_ip_recursive on 本身不是漏洞。它会沿地址链反向查找最后一个非可信地址,前提是 set_real_ip_from 只包含真正受控的代理地址。如果可信范围配置为全网,递归解析就失去了安全边界。配置与链路检查在服务器上先展开完整 Nginx 配置,避免只检查单个文件。include 引入的配置经常是问题来源。sudo nginx -T 2>&1 | grep -nE \ 'set_real_ip_from|real_ip_header|real_ip_recursive|allow |deny |proxy_set_header' # 检查 80/443 是否直接暴露在公网地址 sudo ss -lntp | grep -E ':(80|443)[[:space:]]' # 查看近期连接的实际 TCP 对端 sudo journalctl -u nginx --since '30 min ago' --no-pager随后确认应用到底读取哪个值。常见框架可能读取 REMOTE_ADDR、X-Forwarded-For、X-Real-IP,或者启用了类似 ProxyFix、ForwardedHeaders 的中间件。代理层和应用层只能有一套清晰的可信代理规则,不能无条件信任请求头。检查项安全预期源站 80/443仅允许 CDN、负载均衡器或运维网段连接set_real_ip_from只配置官方公布且已核验的代理出口网段X-Forwarded-For由边缘节点覆盖或规范追加,不直接采信外部值后台鉴权账号、会话、MFA 等业务鉴权优先,IP 仅作附加条件日志同时保留 TCP 对端、解析后客户端地址和完整转发链安全配置示例以下示例假设 192.0.2.0/24 和 2001:db8:100::/48 是经过核验的代理出口地址。实际部署必须替换为供应商当前公布的地址,并建立网段变更流程。# 只信任明确的反向代理/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; # 向上游传递解析后的地址,并保留主机信息 location / { proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; proxy_pass }如果边缘代理已经覆盖 X-Forwarded-For,源站应按该产品的规则解析。如果边缘只是追加地址,需要明确地址链中每一跳的行为。多层代理场景中,不建议仅凭“取第一个 IP”或“取最后一个 IP”编写业务代码。日志留痕只记录 remote_addr 不足以回溯代理链。启用 realip 后,remote_addr 是解析后的客户端地址,而 realip_remote_addr 保存建立 TCP 连接的原始对端。建议同时记录二者、原始转发头、请求标识和上游响应。log_format proxy_audit escape=json '{' '"time":"$time_iso8601",' '"request_id":"$request_id",' '"host":"$host",' '"peer_ip":"$realip_remote_addr",' '"client_ip":"$remote_addr",' '"xff":"$http_x_forwarded_for",' '"method":"$request_method",' '"uri":"$request_uri",' '"status":$status,' '"bytes":$body_bytes_sent,' '"upstream":"$upstream_addr",' '"upstream_status":"$upstream_status"' '}'; access_log /var/log/nginx/proxy_audit.log proxy_audit;变更后先检查语法,再平滑加载并观察错误日志。sudo nginx -t && sudo systemctl reload nginx sudo tail -F /var/log/nginx/proxy_audit.log /var/log/nginx/error.log排查伪造时可重点关注三类记录:peer_ip 不属于可信代理网段但带有 X-Forwarded-For;client_ip 为回环、链路本地或内网地址;同一 peer_ip 在短时间内提交大量不同的地址链。源站边界加固修正 Nginx 配置仍不够。只要源站允许互联网直接访问,就存在绕过 CDN 防护、限速和缓存策略的可能。应在云安全组、主机防火墙或上游 ACL 中限制 80/443,仅允许代理出口地址。保留独立的运维入口,避免调整规则时把 SSH 或管理通道一并封禁。先添加新代理网段并验证流量,再删除旧网段,防止 CDN 节点切换导致业务中断。IPv4 和 IPv6 必须同时限制,很多源站只封了 IPv4,却仍通过 AAAA 记录或公网 IPv6 暴露。不要依赖隐藏源站 IP。历史 DNS、证书透明度记录和邮件服务都可能使地址暴露。回归验证修复完成后,至少验证以下四组请求:# 1. 正常通过域名和 CDN 访问,应保持业务可用 curl -sk -o /dev/null -w '%{http_code}\n' # 2. 非可信地址直连源站,预期超时、拒绝连接或被防火墙丢弃 curl -sk --connect-timeout 5 \ --resolve portal.test:443:203.0.113.10 \ -o /dev/null -w '%{http_code}\n' # 3. 外部伪造回环地址,后台仍应返回 401/403 curl -sk -H 'X-Forwarded-For: 127.0.0.1' \ -o /dev/null -w '%{http_code}\n' # 4. 正常请求后核对 peer_ip、client_ip、xff 和 request_id sudo tail -n 20 /var/log/nginx/proxy_audit.log风险与修复建议立即删除 0.0.0.0/0、::/0 等过宽的 set_real_ip_from 配置。在网络层限制源站入口,不让非代理流量到达 Nginx。后台和内部 API 不应仅依赖来源 IP,应补充可靠的身份认证和授权检查。对回环、私网、链路本地地址出现在外部转发链中的情况建立告警。保存配置变更时间、测试请求 ID 和修复前后日志,便于复盘及确认影响范围。若历史日志只记录了改写后的地址,不能直接把它当作攻击源;应结合负载均衡日志、防火墙流日志和 CDN 请求 ID 交叉确认。总结网站使用 CDN 或反向代理后,真实 IP 不是一个普通请求头,而是一条需要明确认证边界的数据链。验证时应同时检查源站暴露、可信代理范围、应用取值、访问控制和日志字段。比较稳妥的落地方式是:网络层只允许代理访问源站,Nginx 只信任明确代理网段,业务后台继续执行独立鉴权,并在日志中同时保留原始 TCP 对端和解析后的客户端地址。 网络请求、日志与边界流量分析示意 服务器、云资产与权限边界梳理示意
21小时前21小时 这类接入建议分三层验收:客户端 IP 是否可信、源站是否只能被代理访问、日志是否能还原完整链路。只看页面能打开不够。 1. 真实 IP 只接受可信代理写入 Nginx 不要无条件信任 X-Forwarded-For,否则客户端自己加一个请求头就能伪造 IP。应当只信任 CDN 官方公布的出口网段,并确认这些网段有自动更新机制: set_real_ip_from 203.0.113.0/24; # 示例,替换为 CDN 官方网段 set_real_ip_from 2001:db8:1234::/48; real_ip_header X-Forwarded-For; real_ip_recursive on; 如果厂商提供专用头,例如 CF-Connecting-IP,优先按厂商文档使用,并确认 CDN 会覆盖而不是透传客户端提交的同名头。后面还有一层自建反代时,每一跳的信任范围都要明确,应用框架里的 trusted proxies 也要同步配置。 可以直接做伪造测试: curl -sS -H 'X-Forwarded-For: 1.2.3.4' curl -sS -H 'X-Real-IP: 5.6.7.8' 最终应用和日志中的客户端地址不应直接变成手工填写的值。若使用 PROXY protocol,还要同时限制监听端口来源,否则直接连接该端口也可能伪造协议头。 2. 源站边界要从外部网络验证 源站的 80/443 应只允许 CDN IPv4、IPv6 网段,SSH/管理端口只允许 VPN 或堡垒机。常见遗漏是只封了 IPv4,AAAA 对应的 IPv6 源站仍可直连。 在一台不属于 CDN 的外部主机上绕过 DNS 测试: curl -vk --connect-timeout 5 \ --resolve example.com:443:源站IP \ 正确结果应是超时、拒绝连接,或者在源站入口被明确拒绝,而不是返回正常业务页面。源站侧同时抓包确认实际对端: sudo tcpdump -ni any 'tcp dst port 443' sudo ss -tn state established '( sport = :443 )' 还要检查历史 DNS、旧域名、邮件头、公开监控记录和证书透明度记录是否暴露过源站。若业务允许,可以在网络白名单之外再加一层 CDN 到源站的 mTLS;单独依赖“秘密请求头”不够,因为源站 IP 一旦暴露,该头可能被重放或泄漏。 3. 日志同时保留客户端地址和代理对端地址 排障时只记录重写后的 $remote_addr 会丢失证据。Nginx 可同时记录真实 IP、直接连接者、原始转发链及请求 ID: log_format trace escape=json '{"time":"$time_iso8601",' '"client_ip":"$remote_addr",' '"peer_ip":"$realip_remote_addr",' '"xff":"$http_x_forwarded_for",' '"host":"$host",' '"method":"$request_method",' '"uri":"$uri",' '"status":$status,' '"request_time":$request_time,' '"request_id":"$request_id",' '"cdn_request_id":"$http_cf_ray"}'; access_log /var/log/nginx/access_trace.log trace; cdn_request_id 应替换为实际厂商的链路 ID。URI 中如果可能带 token,建议改记不含参数的 $uri,不要直接记录完整 $request_uri。日志最好实时投递到独立日志节点,统一 NTP 时间,并限制本机业务账号删除或修改历史日志。 最后建议形成固定验收表:正常经 CDN 访问、伪造转发头、直接访问 IPv4 源站、直接访问 IPv6 源站、错误 Host/SNI、绕过 CDN 的大请求各测一次。这样比单看 IP 查询页面更容易发现信任链和边界配置问题。
创建帐户或登录后发表意见