发布于1小时前1小时 背景网站接入 CDN、WAF 或负载均衡后,源站通常不再直接面对访客。这个架构能改善访问速度并降低源站暴露风险,但也引入了一条容易被忽略的信任链:客户端、加速节点、反向代理、应用服务器。在一次已授权的网站安全检查中,应用根据 X-Forwarded-For 判断管理后台访问来源,Nginx 日志也直接记录该请求头。测试发现源站仍允许公网直连,攻击者可以绕过 CDN,伪造 X-Forwarded-For: 127.0.0.1,使应用误以为请求来自本机。与此同时,安全日志记录的也是伪造地址,给后续溯源造成干扰。以下检查应仅用于自有系统或明确授权范围。重点不是构造攻击流量,而是确认代理信任边界、源站暴露情况和日志证据是否可靠。问题定位这类问题通常同时涉及网络边界、Web 服务器配置和应用逻辑,建议按请求链逐层确认。检查位置重点内容常见异常DNS 与 CDN域名是否全部经过加速节点历史解析记录泄露源站地址源站防火墙80、443 端口允许哪些来源向整个互联网开放Nginxreal_ip 模块信任哪些代理信任 0.0.0.0/0 或直接使用请求头应用是否用客户端 IP 执行鉴权仅凭 X-Forwarded-For 放行管理接口日志是否同时保留连接地址和还原地址只记录可由客户端伪造的字段第一步:确认源站是否可以被绕过先从资产侧核对当前 DNS、历史证书、旧域名和云主机公网地址。拿到疑似源站地址后,不要做目录爆破,可使用 Host 头进行一次低影响验证,观察证书、响应头和页面摘要是否与正式站点一致。dig +short example.com curl -kI --resolve example.com:443:203.0.113.10 openssl s_client -connect 203.0.113.10:443 -servername example.com </dev/null 2>/dev/null \ | openssl x509 -noout -subject -issuer -dates如果指定源站地址后仍能获得正式站点内容,说明 CDN 并不是强制入口。此时即便 CDN 上启用了 WAF、限速和访问控制,直连源站仍可能绕开这些策略。第二步:验证代理头是否被无条件信任在授权测试窗口内,分别通过正式域名和源站地址发送普通请求,并加入测试专用地址。192.0.2.0/24 属于文档保留网段,适合作为日志标记,不应使用真实第三方地址。curl -k \ -H 'X-Forwarded-For: 192.0.2.123' \ -H 'X-Request-ID: audit-realip-20250308' curl -k --resolve example.com:443:203.0.113.10 \ -H 'X-Forwarded-For: 192.0.2.123' \ -H 'X-Request-ID: audit-origin-20250308'随后在 Nginx 与应用日志中搜索 X-Request-ID。需要回答三个问题:连接源地址是谁、Nginx 还原后的地址是谁、应用最终拿到的地址是谁。如果三者无法区分,当前日志不足以支持可靠溯源。技术分析:三个地址不要混为一谈连接地址:与 Nginx 建立 TCP 连接的节点地址。经 CDN 访问时通常是 CDN 出口地址。代理声明地址:X-Forwarded-For 或厂商专用头中的值,本质上是 HTTP 输入,默认不可信。还原客户端地址:Nginx 在确认连接方属于可信代理后,通过 real_ip 模块计算出的地址。错误配置往往是直接把 $http_x_forwarded_for 当成客户端地址,或者配置 set_real_ip_from 0.0.0.0/0。后者等于允许任意连接方改写 $remote_addr,风险不仅影响日志,还可能影响限速、封禁和后台访问控制。第三步:配置 Nginx 的可信代理边界可信代理网段应从 CDN 或负载均衡厂商的官方地址清单获取,并纳入变更管理。下面使用示例网段表示,不能原样用于生产。# /etc/nginx/conf.d/realip.conf # 仅信任实际会连接源站的代理网段 set_real_ip_from 198.51.100.0/24; set_real_ip_from 2001:db8:100::/48; # 按实际架构选择标准头或厂商专用头 real_ip_header X-Forwarded-For; real_ip_recursive on; # 同时记录 TCP 对端、还原地址和原始代理头 log_format security_json escape=json '{"time":"$time_iso8601",' '"request_id":"$request_id",' '"peer_ip":"$realip_remote_addr",' '"client_ip":"$remote_addr",' '"xff":"$http_x_forwarded_for",' '"host":"$host",' '"method":"$request_method",' '"uri":"$request_uri",' '"status":$status,' '"bytes":$body_bytes_sent,' '"referer":"$http_referer",' '"ua":"$http_user_agent",' '"request_time":$request_time}'; access_log /var/log/nginx/access_security.json security_json;$realip_remote_addr 用于保留原始 TCP 对端,$remote_addr 则是在 real_ip 模块处理后的客户端地址。两者同时记录,才能判断请求是否经过预期代理。修改配置后先执行语法检查和热加载,避免因配置错误中断服务。nginx -t systemctl reload nginx journalctl -u nginx --since '10 minutes ago' --no-pager第四步:限制源站只接受可信入口real_ip 配置只能解决地址还原,不能代替网络隔离。更稳妥的做法是在云安全组、主机防火墙或上游 ACL 中,仅允许 CDN、负载均衡和运维出口访问源站 80、443 端口。以 nftables 为例,可以维护独立地址集合。执行前应确认当前连接不会被切断,并准备控制台回滚路径。table inet filter { set trusted_proxy_v4 { type ipv4_addr flags interval elements = { 198.51.100.0/24 } } chain input { type filter hook input priority 0; policy drop; ct state established,related accept iifname "lo" accept tcp dport 22 ip saddr 192.0.2.10 accept tcp dport { 80, 443 } ip saddr @trusted_proxy_v4 accept } }如果加速节点地址变化频繁,应使用定时任务从官方 HTTPS 地址拉取清单,校验格式后生成新集合,再以原子方式替换。不要直接把未经校验的远程内容拼接进防火墙命令。第五步:检查应用层权限边界客户端 IP 适合用于风险判断、审计和辅助限速,不适合成为后台鉴权的唯一条件。常见危险逻辑包括“IP 为 127.0.0.1 即管理员”“X-Forwarded-For 位于办公网即跳过登录”。后台接口至少应同时具备身份认证、角色授权和操作审计。若确实需要基于来源限制,应使用 Nginx 还原后的可信地址,并将其作为附加条件。# 管理路径示例:来源限制只是附加控制,应用仍需正常登录与授权 location /admin/ { allow 192.0.2.0/24; deny all; 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-Request-ID $request_id; proxy_pass }还要注意覆盖而不是透传不可信头。边缘代理应清理客户端提交的同名内部头,再写入自己的标准值;源站只信任边缘代理。如果存在 CDN、负载均衡、Ingress 多层代理,需要逐跳梳理谁追加、谁覆盖、谁解析。日志排查方法完成配置后,可用 jq 对 JSON 日志做快速检查。以下命令用于发现 TCP 对端不属于预期代理、还原地址异常或同一请求标识跨层不一致的情况。# 查询测试请求 jq -c 'select(.request_id | test("audit-(realip|origin)"))' \ /var/log/nginx/access_security.json # 统计实际连接源地址 jq -r '.peer_ip' /var/log/nginx/access_security.json \ | sort | uniq -c | sort -nr | head -20 # 检查代理头含多级地址的请求 jq -c 'select(.xff != "" and (.xff | contains(","))) | {time,request_id,peer_ip,client_ip,xff,uri,status}' \ /var/log/nginx/access_security.json日志进入集中平台后,建议建立以下告警:源站收到非可信代理连接、管理路径出现来源异常、同一 client_ip 在短时间内跨多个国家或自治域、X-Forwarded-For 链长度突变、peer_ip 与已登记代理清单不匹配。风险与修复建议最高优先级:通过安全组或防火墙关闭公网直连源站,只开放可信代理地址。高优先级:删除 set_real_ip_from 0.0.0.0/0,只保留官方代理网段,并同时覆盖 IPv4 与 IPv6。高优先级:禁止应用仅凭客户端 IP 或代理头授予管理权限。中优先级:日志同时保存 peer_ip、client_ip、原始代理头、请求标识和响应状态。中优先级:将 CDN 地址清单更新纳入监控,更新失败时保留上一个有效版本,不要自动放宽为全网。中优先级:定期用指定 Host 访问源站地址,确认直连请求已被丢弃或返回固定拒绝页。总结网站加速不是简单地在域名前增加一层 CDN。真正需要维护的是一条明确的信任链:只有指定代理能连接源站,只有来自这些代理的转发头可以参与地址还原,应用不能把 IP 当成身份凭据,日志必须同时保留原始对端和还原结果。这套检查对 CDN、云负载均衡、Kubernetes Ingress 和自建 Nginx 代理都适用。排查时先确认源站暴露,再验证请求头信任,最后核对应用权限和日志证据,通常能较快发现加速架构中的边界缺口。 网络请求、日志与边界流量分析示意 服务器、云资产与权限边界梳理示意
13分钟前13分钟 这类链路最容易出问题的点,不是“有没有传 X-Forwarded-For”,而是谁有资格写这个头。建议先把信任边界固定为:公网用户 → CDN → 源站 Nginx → 应用,源站不要直接接受公网访问。 源站侧先限制入口,只允许 CDN 回源网段访问 80/443。否则攻击者可以绕过 CDN 直连源站,自己构造 X-Forwarded-For: 127.0.0.1,基于客户端 IP 的后台白名单、限流和审计都会失效。可以先检查源站是否暴露: dig +short origin.example.com curl -vk --resolve ss -lntp | grep -E ':(80|443)\b' Nginx 不要直接使用任意来源的 XFF,而应只信任 CDN 官方公布的出口网段。以 CDN 使用 X-Forwarded-For 为例: http { # 仅填写 CDN 官方回源网段,并建立自动更新机制 set_real_ip_from 192.0.2.0/24; set_real_ip_from 2001:db8:1234::/48; real_ip_header X-Forwarded-For; real_ip_recursive on; log_format trace '$time_iso8601 ' 'client=$remote_addr ' 'peer=$realip_remote_addr ' 'xff="$http_x_forwarded_for" ' 'host="$host" request="$request" ' 'status=$status upstream=$upstream_addr ' 'urt=$upstream_response_time rt=$request_time'; access_log /var/log/nginx/access_trace.log trace; server { 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_pass } } } $remote_addr 在 realip 模块处理后是还原出的客户端地址;$realip_remote_addr 保留实际与 Nginx 建连的上游地址,通常应当落在 CDN 网段。两个字段一起记录,比只记一个 XFF 更适合排查伪造头、CDN 节点异常和绕源请求。 如果 CDN 提供专用真实 IP 头,例如 CF-Connecting-IP 一类,优先按厂商文档使用该头,并继续通过 set_real_ip_from 限定可信来源。不要为了“兼容”配置: set_real_ip_from 0.0.0.0/0; set_real_ip_from ::/0; 权限判断也建议只在一个位置完成。应用如果已经从可信 Nginx 接收到规范化后的 X-Real-IP,就不要再自行取 XFF 的第一个或最后一个元素;不同框架对代理层数、取值方向的定义并不一致。后台管理权限最好仍以身份认证和明确授权为主,IP 白名单只作为附加条件。 排查时可以做三组对照请求: # 1. 正常经过 CDN curl -sS -D- -o /dev/null # 2. 经 CDN 注入伪造 XFF,确认不会被直接采信 curl -sS -D- -H 'X-Forwarded-For: 127.0.0.1, 10.0.0.1' \ -o /dev/null # 3. 直连源站,预期应被防火墙或 Nginx 拒绝 curl -vk --resolve \ -H 'X-Forwarded-For: 127.0.0.1' \ 同时观察日志: tail -f /var/log/nginx/access_trace.log nginx -T | grep -nE 'real_ip|set_real_ip|log_format|proxy_set_header' 正常情况下,第一、二组请求的 peer 应是 CDN 节点,client 应是实际出口 IP;伪造的头即使保留在原始 xff 字段里,也不应让权限判断变成 localhost。第三组应该无法到达业务。如果还能成功,优先修防火墙、安全组和源站域名泄露,而不是继续调整应用层取 IP 的代码。 另外注意 CDN 网段会变更。静态复制一次后长期不更新,后续常见表现是部分地区突然都记录成 CDN 节点 IP。更新脚本应先校验下载结果,生成独立配置文件,再执行 nginx -t 成功后 reload,避免空文件或错误网段直接上线。
创建帐户或登录后发表意见