发布于23小时前23小时 背景网站为了抗流量、降低回源延迟,通常会在源站前部署 CDN、WAF 或自建反向代理。这个架构最容易被忽略的问题,不是缓存命中率,而是客户端真实 IP 的信任边界。如果源站无条件采用请求中的 X-Forwarded-For 或 X-Real-IP,攻击者就可能伪造来源地址,影响后台访问控制、接口限速、审计追踪和封禁策略。本文以已授权的网站与服务器测试为前提,说明如何检查代理链、验证配置、完善日志,并给出可落地的修复方案。典型场景某网站使用“CDN → Nginx → 应用服务”的链路。后台路径只允许办公网访问,应用根据 X-Forwarded-For 判断客户端 IP。测试时发现:源站公网端口可以直接访问,并且 Nginx 信任任意来源提交的 X-Forwarded-For。这类问题通常由两个配置缺口叠加产生:源站防火墙没有限制回源地址,攻击者可以绕过 CDN 直连源站。Nginx 的 realip 模块信任范围过大,或者应用直接解析用户可控请求头。问题定位先确认实际链路,不要只看域名解析结果。需要同时检查 DNS、监听端口、Nginx 配置和边界防火墙。# 查看域名解析及可能的 CDN CNAME dig +short example.test dig CNAME example.test # 在源站检查监听地址和端口 ss -lntp # 输出 Nginx 完整生效配置,重点搜索 real_ip 与 proxy_set_header nginx -T 2>&1 | grep -nE 'set_real_ip_from|real_ip_header|real_ip_recursive|proxy_set_header|log_format' # 检查主机防火墙规则 nft list ruleset # 使用 firewalld 的环境也可执行 firewall-cmd --list-all如果源站对公网开放 80 或 443,还应在授权范围内使用源站地址进行回源验证。测试时通过 Host 指定目标虚拟主机,避免把结果误判为默认站点响应。# 仅在已授权目标上执行,将 192.0.2.10 替换为测试源站地址 curl -k -I --resolve example.test:443:192.0.2.10 # 检查服务端是否错误采信外部提交的真实 IP 头 curl -k --resolve example.test:443:192.0.2.10 \ -H 'X-Forwarded-For: 127.0.0.1' \ -H 'X-Real-IP: 127.0.0.1' \ 的 remote_addr 默认表示与当前服务器建立 TCP 连接的对端地址。只有当这个对端是可信代理时,代理传入的真实 IP 头才有可信基础。set_real_ip_from 用来声明可信代理网段。若配置为 0.0.0.0/0,相当于允许任意客户端改写来源 IP。real_ip_recursive 开启后,Nginx 会沿地址链从右向左剥离可信代理,直到遇到第一个不可信地址。因此,可信代理列表必须精确,并随 CDN 官方回源网段变化及时更新。变量含义建议用途$remote_addrrealip 模块处理后的客户端地址应用限速与常规访问日志$realip_remote_addr改写前的 TCP 对端地址确认请求是否来自可信 CDN$http_x_forwarded_for原始请求头内容,可能由客户端影响仅用于取证留痕,不直接做鉴权$request_id请求关联标识串联代理与应用日志安全配置示例下面配置假设 CDN 回源网段为文档示例地址。生产环境必须替换为供应商正式公布的地址,并通过变更流程维护。http { # 仅信任明确的 CDN/WAF 回源网段,禁止使用 0.0.0.0/0 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",' '"client_ip":"$remote_addr",' '"peer_ip":"$realip_remote_addr",' '"xff":"$http_x_forwarded_for",' '"host":"$host",' '"method":"$request_method",' '"uri":"$request_uri",' '"status":$status,' '"bytes":$body_bytes_sent,' '"referer":"$http_referer",' '"user_agent":"$http_user_agent",' '"upstream":"$upstream_addr",' '"upstream_status":"$upstream_status",' '"request_time":$request_time,' '"upstream_time":"$upstream_response_time"}'; access_log /var/log/nginx/security_access.json security_json; server { listen 443 ssl; server_name example.test; 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_set_header X-Forwarded-Proto $scheme; proxy_pass /> } } }配置修改后先进行语法检查,再平滑加载,避免因手工维护网段造成服务中断。nginx -t && nginx -s reload # 观察加载后的错误日志 journalctl -u nginx --since '10 minutes ago' --no-pager tail -n 100 /var/log/nginx/error.log源站边界加固只修正请求头解析还不够。更稳妥的方案是在网络层限制 80/443 只接受 CDN 或 WAF 回源地址,并将运维入口放入 VPN、堡垒机或专用管理网。# nftables 示例:执行前先确认远程管理通道,避免误封 nft add table inet webfilter nft 'add chain inet webfilter input { type filter hook input priority 0; policy accept; }' # 允许已建立连接 nft add rule inet webfilter input ct state established,related accept # 允许示例 CDN 网段访问 HTTPS nft add rule inet webfilter input ip saddr 192.0.2.0/24 tcp dport 443 accept nft add rule inet webfilter input ip6 saddr 2001:db8:100::/48 tcp dport 443 accept # 拒绝其他来源直连 HTTPS;上线前应通过维护窗口验证 nft add rule inet webfilter input tcp dport 443 counter drop云服务器还应同步检查安全组、负载均衡监听器和公网 IP 绑定。只在主机防火墙限制,而安全组仍全开放,会增加误配置恢复和旁路访问风险;反之,只依赖安全组也不利于主机侧形成完整控制与计数日志。日志排查方法验证重点是比较 peer_ip、client_ip 与 xff 三者关系。正常情况下,peer_ip 应属于可信 CDN 网段;client_ip 是剥离可信代理后的用户地址;xff 用于保留原始链路,但不能单独作为安全决策依据。# 查询 TCP 对端不属于预期回源网段的请求 jq -c 'select(.peer_ip | startswith("192.0.2.") | not)' \ /var/log/nginx/security_access.json # 检查声称来自本机或内网的 X-Forwarded-For jq -c 'select(.xff | test("(^|, ?)(127\\.|10\\.|192\\.168\\.|172\\.(1[6-9]|2[0-9]|3[01])\\.)"))' \ /var/log/nginx/security_access.json # 按请求标识关联单次访问 jq -c 'select(.request_id == "待查询的请求ID")' \ /var/log/nginx/security_access.json若发现 peer_ip 是公网普通地址,而 xff 声称为 127.0.0.1、办公网或管理网地址,应优先排查源站旁路访问和 realip 信任范围。若 peer_ip 确实属于 CDN,但地址链异常,则需要确认 CDN 的请求头覆盖策略,避免其简单透传客户端已有的同名头。权限边界与应用层注意事项后台管理权限不要只依赖来源 IP。至少叠加强认证、独立身份鉴别和会话安全控制。应用应读取由受控反向代理覆盖后的标准字段,不要自行从 X-Forwarded-For 左侧取第一个地址。代理到应用的端口不应直接暴露公网。可绑定 127.0.0.1、Unix Socket 或内部专用网卡。缓存规则不要覆盖登录态、管理接口、验证码和包含敏感信息的响应。对 Authorization、Cookie 与 Set-Cookie 明确设置旁路策略。保留 CDN 边缘日志、Nginx 访问日志、应用认证日志和主机审计日志,并统一时间同步与 request_id。修复后的验证清单从非 CDN 地址直连源站 80/443,应被安全组或主机防火墙拒绝。通过正常域名访问,业务响应和缓存功能应保持正常。伪造 X-Forwarded-For 后,日志中的 client_ip 不应被任意改写。peer_ip 应稳定落在已登记的 CDN/WAF 回源网段。应用收到的 X-Real-IP、X-Forwarded-For 与 Nginx 解析结果一致。管理接口同时具备身份认证,不因伪造来源地址获得额外权限。日志轮转、留存周期、文件权限和集中采集状态均正常。风险与修复建议此类问题的风险通常不止是“日志 IP 不准确”。如果限速、后台白名单、风控规则或审计系统依赖错误的来源地址,可能进一步造成访问控制绕过、告警失真和事件追踪困难。推荐按优先级处理:先限制源站只能被可信代理访问;再收紧 set_real_ip_from;随后统一应用层取值方式;最后补齐结构化日志和异常检测。CDN 网段变更应使用受控脚本定期拉取、校验并生成配置,但不要未经审计直接覆盖生产配置。总结网站加速架构中的关键安全点,是明确每一跳的信任关系。TCP 对端是否可信、真实 IP 头由谁写入、源站能否被绕过、应用依据什么做权限判断,这四个问题必须一起验证。通过网络层限制回源、精确配置 realip、保留改写前后地址并关联应用日志,才能让加速能力、权限边界和日志取证同时成立。 网络请求、日志与边界流量分析示意 服务器、云资产与权限边界梳理示意
23小时前23小时 这类验证的重点不是“日志里能否看到客户端 IP”,而是确认只有 CDN 节点有权改写客户端 IP。建议分三组测试:正常经 CDN、伪造转发头、绕过 CDN 直连源站。 Nginx 侧应只信任 CDN 官方公布的出口网段,不要使用 set_real_ip_from 0.0.0.0/0。下面以 CDN 使用 X-Forwarded-For 为例;如果厂商提供专用头,应替换为对应字段: set_real_ip_from 203.0.113.0/24; set_real_ip_from 2001:db8:100::/48; real_ip_header X-Forwarded-For; real_ip_recursive on; log_format edge_combined escape=json '{"time":"$time_iso8601",' '"request_id":"$request_id",' '"remote_addr":"$remote_addr",' '"peer_addr":"$realip_remote_addr",' '"xff":"$http_x_forwarded_for",' '"host":"$host",' '"request":"$request",' '"status":$status,' '"bytes":$body_bytes_sent,' '"ua":"$http_user_agent"}'; access_log /var/log/nginx/edge_access.log edge_combined; 这里的两个地址含义不同:$remote_addr 是经过 realip 模块处理后的客户端地址,$realip_remote_addr 保留实际连接到源站的对端地址,通常应为 CDN 节点。两者同时记录,后续才能判断是谁提交了转发头。 先验证正常链路: curl -sS -D- tail -f /var/log/nginx/edge_access.log | jq . 正常情况下,日志中的 peer_addr 应落在 CDN 官方网段,remote_addr 才是访问端公网 IP。随后主动注入伪造头: curl -sS \ -H 'X-Forwarded-For: 198.51.100.77, 192.0.2.88' 此时要结合厂商行为判断:有的 CDN 会覆盖该头,有的会在末尾追加。无论哪种,Nginx 都只能沿着“已信任代理链”向左解析,不能让用户自行提交的任意地址成为最终客户端 IP。建议同时检查原始 xff 和解析后的 remote_addr,不要只看应用层打印结果。 更关键的是验证源站是否能被绕过。先取得源站地址,再绕过 DNS 直接访问: curl -vk --resolve example.com:443:ORIGIN_IP \ \ -H 'X-Forwarded-For: 198.51.100.77' 理想结果是连接被防火墙、安全组或源站 Nginx 拒绝。若仍能返回业务内容,即使 realip 配置正确,也存在绕过 CDN、绕过限速/WAF 的入口。源站入口应仅放行 CDN 网段;条件允许时再加 CDN 到源站的 mTLS 或带轮换机制的鉴权头,避免只依赖可伪造的普通请求头。 # 示例:先保留管理通道,实际执行前确认 CDN 网段完整 iptables -A INPUT -p tcp --dport 443 -s 203.0.113.0/24 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -s ADMIN_IP/32 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j DROP 最后建议做两个持续性检查:一是定期同步并审计 CDN 网段变更,防止旧网段被回收后仍受信;二是对日志中 peer_addr 不属于 CDN 网段、转发链异常增长、同一请求 ID 在 CDN 与源站记录不一致的情况告警。日志轮转后也应做集中留存,并限制原始访问日志读取权限,因为转发头、查询参数和 Cookie 可能包含敏感信息。
创建帐户或登录后发表意见