1. 一句话

面板类工具(宝塔等)在 CDN / 真实 IP 场景下会往 http 全局写:

set_real_ip_from 0.0.0.0/0;
set_real_ip_from ::/0;
real_ip_header X-Forwarded-For;

语义是「任何客户端发来的 X-Forwarded-For 我都采信」。后果:nginx access log 第一列的来源 IP 由请求方自己决定,所有基于日志的「有没有人来过」审计全部失效——攻击者可以让自己的访问在日志里变成机主的 IP。


2. 复现(一条 curl)

curl -k -H 'X-Forwarded-For: 1.2.3.4' https://host/
# access log:  1.2.3.4 - - [21/Sep/2026:22:22:20 +0800] "GET / HTTP/2.0" 200 1104

实测:伪造 1.2.3.4 → 日志记成 1.2.3.4;伪造机主自己的公网 IP → 日志记成机主。用 --resolve 直接把 Host 指向本机也一样生效。


3. 为什么最容易误判

  • 结论正好顺眼:日志「很干净,只有我自己的 IP」,就是想看到的答案,于是收工。而这份干净是伪造得出来的。
  • 反向噪音:日志里出现成片「服务器自己的公网 IP + HTTP/1.0 + Referer: http://127.0.0.1/<同路径> + 可疑 UA」,容易被解释成「本机巡检脚本」。这几个字段同时出现时,来源存疑,不能当本机行为读。
  • 本机测不出来:从服务器上 curl 打自己的公网域名,源就是本机;只要本机在可信列表里,伪造照样生效,测试通过但其实没测到点。必须换一台外部机器测。

4. 确认是否中招

nginx -T | grep -n "set_real_ip_from\|real_ip_header"

出现 0.0.0.0/0 或 ::/0 即中招。宝塔的落点是 /www/server/panel/vhost/nginx/real_cdn_ip.conf,经 include /www/server/panel/vhost/nginx/*.conf; 在 http 上下文全局加载,优先级高于单个 vhost。


5. 修法

无 CDN 直连的站点,正确配置就是「谁都不信」;有 CDN 才列真实回源段:

# 只信任本机转发
set_real_ip_from 127.0.0.1;
set_real_ip_from ::1;
real_ip_header X-Forwarded-For;
nginx -t && systemctl reload nginx

验证必须从另一台机器发:

ssh other-host "curl -k -H 'X-Forwarded-For: 9.9.9.9' https://target/"
# 期望:日志记 other-host 的真实 IP,而不是 9.9.9.9

副作用是正向的:$remote_addr 恢复真实后,proxy_set_header X-Real-IP $remote_addr 传给后端的值也不再可伪造,后端按 IP 做的限流才真正成立。

该文件由面板生成,之后在面板里再动 CDN / 真实 IP 相关设置会被重写,改完要复查。

6. 顺带:订阅/配置文件的路径本身就是凭据

自建代理的 /sub/xxx.yaml 里装着节点 UUID(等于节点钥匙),路径即凭证。别用 clash.yaml 这类可猜名。扫描器是全端口、全路径跑的,服务器日志里成片的 /xmlrpc.php、/xx/.env 就是证据——只是还没撞到你的文件名。

做法:openssl rand -hex 8 生成 16 位随机串作文件名,旧文件 mv 掉(不是删,改完由机主重新导入订阅)。alias 目录默认不开 autoindex,目录列表返回 403,只剩文件名这一层防护,所以文件名必须是不可猜的。


7. 相关

来源:2026-09-21 排查一台洛杉矶自建代理 VPS(nginx + xray + cli-proxy-api + new-api)。「无第三方盗用」这个结论成立,但当时给出的推导过程不成立——日志来源 IP 可伪造,只是恰好没人伪造。

本文归档于个人知识库 · 领域:CS & AI · 模块:04 Project_CS_AI/Network