ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CDN 回源 IP 导致 nginx 日志失真:我是怎么把真实客户端 IP 找回来的

CDN 回源 IP 导致 nginx 日志失真:我是怎么把真实客户端 IP 找回来的 变量探索SEQVEC上一篇《蜜罐里的攻击者画像》里我把「先确认这个 IP 是不是真的」放在了最前面标成第 0 步—— 因为它是所有分析的前提前提错了后面算得再认真都是白算。那一步只写了一小段这一篇把它展开异常是怎么冒出来的、根因在哪、怎么修、修完还有什么没堵上。先说结论数据没丢也不用重采。真实 IP 一直都在日志里是我读错了字段。下面所有数字都是我自己机器上的实测。IP 都打了码保留前两段一是没必要把完整地址挂出去二是那个头名我更不能写全 —— 原因写在第三节。一、异常一个 IP怎么可能有 14 种身份给蜜罐日志做 IP 画像的时候出现了一个说不通的现象43.175.███.███ 34 次 打过 8 个不同子域名 出现过 9 种不同 UA 43.175.███.███ 29 次 打过 5 个不同子域名 出现过 14 种不同 UA一个攻击者只有一种工具。一个 IP 上同时出现curl、企业级攻击面扫描、泄露情报采集、还有伪装成 Chrome 的脚本 —— 那是好几家公司在扫不是一个人。而且它还在打我不同的域名。这只可能是一种东西共享中间节点。顺着查下去43.174 / 43.175 这两个段里的 24 个 IP在我抽出的 500 条样本里占了204 条 —— 40.8%。它们属于同一批机房、同一个 AS。也就是说如果我拿这批 IP 去做攻击者画像我画出的是机房的地图不是攻击者的画像。留一条判断手法以后再看到日志里全是同一个机房的 IP用这一条就够了看一个 IP 打了几种 UA、几个 host。真实来源 1 种 UA1–2 个站 中间节点 多种 UA多个站一个 IP 横跨多个站、带着十几种 UA —— 它不是访客它是替访客接电话的那个人。二、根因不是没传真实 IP是传了但源站没读原理其实很简单两句话访客 → CDN 节点 → 回源 → 我的源站 ↑ 源站看到的 TCP 对端地址是 CDN 的回源节点HTTP 是建立在 TCP 上的而真实客户端 IP 在 TCP 层已经丢了—— 因为它不是直接跟我连的。真实 IP 只能靠 HTTP 头部带话过来。所以我这边受影响的不只是蜜罐日志nginx 的 access_log → 假 宝塔的来源统计 → 假 那个登录限制插件的告警邮件 → 假 我自己的分析脚本 → 假全都在看$remote_addr而$remote_addr是回源节点的地址。但真实 IP 其实一直都在9 月 24 号上 CDN 的时候我改过蜜罐的日志格式顺手把xff也记下来了{ip:43.175.███.███,ra:43.175.███.███,xff:160.176.███.███,...}↑ 回源节点当时以为是真的 ↑ 真实访客一直都在也就是说数据没丢是我的分析脚本读的是ip字段没读xff。这件事值得单独说一句 —— 出了这种问题第一反应通常是数据得重采。但大多数时候数据就在那儿只是取数的那一行代码看错了地方。边界要说清楚X-Forwarded-For是标准头任何人都能伪造。所以它适合用来做事后分析不能拿来当访问控制的依据。三、修法CDN 侧 源站两边都要动上一篇我给的是通用两行set_real_ip_from CDN 回源 IP 段; real_ip_header X-Forwarded-For;真去落地的时候撞上一个前提问题我用的 EdgeOne 免费版控制台里拿不到回源 IP 段。set_real_ip_from的作用是只信任这些来源传过来的头。拿不到段这个值就只能写得很宽 —— 而这正是安全上最不该做的事。所以最后的方案是换个方向不管来源改管头名。第 1 步EdgeOne 侧用一个自定义头名把真实 IP 带过来站点加速 → 规则里加一个自定义请求头值是客户端真实 IP随回源请求一起带到源站。关键点是头名不用X-Forwarded-ForX-Forwarded-For 所有扫描器、所有攻击工具都会尝试伪造它 X-Hx-Rc-一串随机字符-Ip 只有知道这个名字的人才构造得出来这个头名我不能写在文章里。它现在就是这个方案唯一的防线 —— 写出来方案当场作废。第 2 步源站 nginx信任这个头set_real_ip_from 0.0.0.0/0; set_real_ip_from ::/0; real_ip_header X-Hx-Rc-同上;配完nginx -t nginx -s reload$remote_addr就变成真实客户端 IP 了。好处是下游一行都不用改日志、上报脚本、统计报表、工作台全部自动变对。两个必须知道的细节①set_real_ip_from 0.0.0.0/0是妥协不是最佳实践。它的意思是所有来源传的头我都信。正常做法是只信任 CDN 回源段 —— 免费版给不了段我只能用头名保密来兜这个底。这个边界第六节单独讲。② 已经有一处map不能删。我原来的配置里有个map $http_x_hx_rc_..._ip $hx_client_ip被十几个站的反代配置引用着proxy_set_header X-Real-IP $hx_client_ip。删了它nginx -t直接报unknown hx_client_ip variable。这条顺带说明一件事应用层一直拿到的是真实 IP只有 nginx 自己的日志是错的。所以问题比我一开始以为的轻。顺手加的一个字段日志格式里加了rara:$realip_remote_addr ← 保留回源节点地址改完之后ip是真实访客、ra是回源节点。留ra是为了以后排查这次请求到底走没走 CDN。四、怎么知道改对了打一枪就看出来不用等第二天从本机打一次就行。我打的是自己站上的一个诱饵路径curl-Acodex-realip-verify/1.0https://我的域名/.env日志里出来这一行{ip:123.156.███.███,ra:114.66.███.███,ua:codex-realip-verify/1.0,host:我的域名}↑ 真实客户端 ↑ 回源节点ip和ra是两个不同的值就说明改造生效了。改造前这两个位置应该是同一个地址。再补一步从不同网络各打一次手机热点、家里、公司看日志里出现的 IP 跟你当时的出口 IP 对不对得上。我改完顺手做了五个入口的健康检查www / studio / linglu-b / lic / ops都正常。五、改完之后立刻冒出来的两个新问题① 最活跃的攻击者变成了我自己。上面那次验证请求EdgeOne 看到的客户端 IP 是我的出口 IP—— 它在真实 IP 榜上直接排到了第一名二十多次。所以在做任何谁在攻击我的统计之前剔除名单得从两个扩到三个127.0.0.1 本机自测 49.233.███.███ 服务器自己的公网 IP监控在访问自己 123.156.███.███ 我自己的出口 IP浏览、手动测试漏掉任何一个你就会把自己的流量当成攻击者的。② 回源节点的 IP 没有消失只是换了地方。它们在ra字段里躺着 —— 这不是残留这是证据。以后怀疑这个 IP 是不是中间节点翻ra比猜快得多。六、这个方案没堵上的地方必须说清楚头名保密挡得住随手扫挡不住盯着你打的人。如果有人知道了我源站的 IP又知道了这个头名他直连源站、自己塞一个假 IP源站照样会信。彻底闭合要两步我目前还没做到① 拿到 EdgeOne 回源 IP 段 → 把 set_real_ip_from 从 0.0.0.0/0 换成真实段 ② 在腾讯云安全组里把 80 / 443 的入站来源限制为回源段 → 绕开 CDN 的直连请求在 TCP 层就被丢掉伪造头也就没意义了这一段我写出来不是谦虚 —— 是提醒看到改两行就解决的方案先问一句它信任了谁。七、回滚动过的两个文件都留了.bak-20261006备份cp-a/www/server/nginx/conf/edgeone-clientip.conf.bak-20261006 /www/server/nginx/conf/edgeone-clientip.confcp-a/www/server/nginx/conf/honeypot-http.conf.bak-20261006 /www/server/nginx/conf/honeypot-http.conf nginx-tnginx-sreload服务器上改配置先想好怎么退回去再动手。这条比配置本身重要。八、如果你也遇到五步照做1 确认 IP 是不是真的 一个 IP 多种 UA、跨好几个站 → 中间节点不是访客 2 翻日志找有没有转发真实 IP 的字段 常见的是 X-Forwarded-For 或 CDN 自己的头 很多平台默认就带着只是你没读 3 源站配 real_ip_header拿不到回源段就用自定义头名 保密 4 打一枪验证 真实 IP 和回源节点应该出现在两个不同的字段里 5 把自己从统计里剔掉 本机、服务器自己、自己的出口 IP —— 三个都要最后这件事真正让我后背发凉的地方不是被扫描 —— 是我拿着一批错的 IP做了一套像模像样的分析还差点写进文章里。数据错的时候分析越认真越离谱因为你根本不会怀疑它。所以我现在的习惯改了一条任何一个数字先问它是从哪个字段来的。关于作者变量探索SEQVEC
返回列表