Nginx反向代理实现CDN回源与源站IP隐藏

CDN加速时源站IP暴露易遭DDoS直击或绕过防护。本文详解Nginx反向代理配置回源规则、allow/deny限制回源IP、处理真实客户端IP,结合CDN鉴权与HTTPS强制,真正实现源站IP隐藏,适合运维人员生产参考。

Nginx反向代理实现CDN回源与源站IP隐藏
封面图:ZuCDN · ZuCDN 原创

CDN(内容分发网络)将静态和动态请求分发到边缘节点,但最终回源请求仍会到达你真正的服务器。如果源站IP暴露,攻击者可以直接绕过CDN发起DDoS、扫描漏洞或耗光带宽。很多团队只配置了CDN域名,却忽略了反向代理层对回源请求的控制。本文从Nginx反向代理的角度,拆解CDN回源配置、源站IP隐藏的具体手段,以及每一步要考虑的风险和验证方法。

CDN回源的本质与暴露源站IP的常见场景

CDN回源是边缘节点向源站请求内容的过程。默认情况下,CDN会把请求的Host头换成源站IP或源站域名,如果你是直接通过A记录将源站域名指向真实服务器IP,那么只要CDN节点能访问,任何人也能通过同样的IP访问。更糟糕的是,很多运维人员会在网站根目录或HTTP响应头中泄露IP信息,比如Server头、X-Forwarded-For、或者直接在HTML里写死的图片路径。

回源请求中的IP透传

当CDN转发请求给源站时,源站看到的来源IP是CDN节点的出口IP,而不是真实访客的IP。如果你在源站Nginx上只配置了简单的proxy_pass而不处理real_ip,那么应用的日志、限速、黑白名单都会失效。与此同时,CDN节点IP往往是一个范围(例如Cloudflare的IP列表是公开的),如果allow/deny指令用错或未配置,任何IP都可能直接访问源站。

最危险的IP泄漏途径

  • DNS记录泄露:历史DNS记录、子域名扫描、直接ping域名可能拿到源站IP。
  • HTTP响应头ServerX-Powered-By、甚至Location跳转暴露内部IP。
  • 证书透明度日志:如果源站单独使用SSL证书,CT日志里会记录IP。
  • 第三方资源引用:比如使用了源站IP的静态资源加载。

理解了这些暴露点,就能针对性地在Nginx反向代理层做出防御。

Nginx反向代理基础配置:只允许CDN回源

反向代理的核心是proxy_pass,但只配这一句等于裸奔。你需要做的是:限制访问源站的IP必须来自CDN节点。

配置allow/deny规则

在Nginx的server块或location块加入:

location / {n    allow 103.21.244.0/22;n    allow 103.22.200.0/22;n    # 以上是Cloudflare的IP段示例,实际需替换为你使用的CDNn    deny all;n    proxy_pass http://backend_upstream;n}

注意deny all必须放在最后,前面的allow顺序无关。CDN回源IP列表会更新(例如Cloudflare每几个月更新一次),建议写个脚本定期从官方API拉取并重载Nginx。另外,如果你的CDN回源还走内网、或者有多个CDN厂商,需要把所有白名单加全。

处理真实客户端IP(real_ip)

只限制回源IP还不够,你必须正确获取访客真实IP,否则应用日志、速率限制都会乱掉。在Nginx的http块中配置:

set_real_ip_from 103.21.244.0/22;nset_real_ip_from 103.22.200.0/22;n# 同样需要包含所有CDN节点IP段nreal_ip_header X-Forwarded-For;nreal_ip_recursive on;

real_ip_recursive on可以让Nginx信任CDN节点IP,并提取最后一个非信任IP作为真实客户端。如果CDN的X-Forwarded-For格式是client_ip, cdn1_ip, cdn2_ip,这样就能正确取出真正的访客IP。

深度隐藏源站IP的进阶策略

限制IP访问只是第一道防线。攻击者仍有可能通过HTTP头、SSL证书、应用层行为推测源站。以下策略可以进一步加固。

屏蔽服务器信息

httpserverlocation块中加入:

server_tokens off;nproxy_hide_header X-Powered-By;nproxy_hide_header X-AspNet-Version;n# 移除Nginx版本号,同时隐藏后端返回的敏感头

同时确保add_header不要把内部IP暴露在LocationAccess-Control-Allow-Origin中。

强制HTTPS与HSTS

如果源站直接开放了80端口,且没有自动跳转HTTPS,攻击者可以通过HTTP请求看到源站响应头信息。配置ssl_certificate并开启add_header Strict-Transport-Security,同时把所有HTTP请求301到HTTPS。更重要的一点:不要让源站单独使用与CDN域名不同的SSL证书,否则任何人都能通过Certificate Transparency日志查到IP。最好的做法是源站只使用CDN颁发的证书(或者自签名证书用于回源),并且源站端口不对外暴露。

利用CDN的回源鉴权机制

主流CDN都支持回源认证:例如阿里云的回源鉴权(在回源请求中添加自定义Header或Token),Cloudflare的Authenticated Origin Pulls(要求回源请求携带TLS客户端证书)。Nginx端需要验证这些凭证,如果请求头部不匹配则拒绝。配置示例(以Cloudflare为例):

ssl_client_certificate /etc/nginx/cloudflare_origin_ca.crt;nssl_verify_client on;n# 仅对CDN回源开启客户端证书验证

然后将CDN的Origin CA证书配置到CDN面板,这样即使攻击者绕过IP限制,也无法通过TLS握手验证。

限制HTTP方法和路径

大部分回源请求只需要GETHEADPOST。在Nginx中你可以拒绝其他方法:

if ($request_method !~ ^(GET|HEAD|POST)$ ) {n    return 405;n}

同时,对敏感路径(如/admin/api/internal)做额外的IP限制或鉴权,避免通过CDN漏洞直接访问。

完整配置示例

下面是一个生产环境可参考的server块,融合了上述策略(假设CDN使用Cloudflare,后端为127.0.0.1:8080):

http {n    set_real_ip_from 103.21.244.0/22;n    set_real_ip_from 103.22.200.0/22;n    # ... 其他CF IP段n    real_ip_header X-Forwarded-For;n    real_ip_recursive on;nn    server {n        listen 443 ssl http2;n        server_name example.com;nn        ssl_certificate /etc/nginx/ssl/cdn_cert.pem;n        ssl_certificate_key /etc/nginx/ssl/cdn_key.pem;n        ssl_client_certificate /etc/nginx/ssl/cf-origin-ca.pem;n        ssl_verify_client on;nn        server_tokens off;n        proxy_hide_header X-Powered-By;nn        # CDN节点白名单n        allow 103.21.244.0/22;n        allow 103.22.200.0/22;n        # ... 其他CF IP段n        deny all;nn        location / {n            proxy_pass http://127.0.0.1:8080;n            proxy_set_header Host $host;n            proxy_set_header X-Real-IP $remote_addr;n            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;nn            # 限制HTTP方法n            if ($request_method !~ ^(GET|HEAD|POST)$ ) {n                return 405;n            }n        }nn        # 强制HTTPS跳转n        error_page 497 =301 https://$host$request_uri;n    }n}

重要:白名单中的IP段必须每季度更新。可以使用官方API脚本(如Cloudflare的cfips.sh)自动生成并nginx -s reload。另外,源站应只监听443端口(或仅限内网),不要对外暴露80和8080。

验证与日常巡检

配置完成后,必须验证源站IP是否真正隐藏。以下方法值得执行:

从外网扫描

使用nmap对源站IP进行端口扫描:nmap -p 80,443 your源站IP。如果只有Nginx的443端口开放,且无法建立HTTPS连接(因为证书不匹配),说明基础隐藏成功。还需要检查curl -I返回的Server头是否只显示nginx(无版本号)。

尝试直接访问

换一个非CDN节点或其他IP的机器,直接请求源站IP:curl -H "Host: yourdomain.com" https://源站IP/。如果返回403或空白,说明allow/deny生效。如果返回正常页面,说明Nginx配置有问题,允许了所有IP。

日志审计

在Nginx的access.log中记录$remote_addr,并定期检查是否出现非CDN节点IP的直接请求。如果出现,立刻排查白名单或防火墙规则。建议配合fail2ban或云防火墙对异常请求做临时封锁。

常见误区与陷阱

  • 只依赖Nginx的allow/deny:Nginx工作在应用层,如果操作系统防火墙(iptables)没有限制,攻击者仍可以绕过Nginx直接访问后端端口。最佳做法是源站服务器只监听内网IP(如127.0.0.1),让Nginx通过Unix Socket或loopback代理,操作系统层面禁止公网IP到后端端口的入站。
  • CDN回源IP列表变化:大多数CDN厂商会公布IP段(如Cloudflare、Akamai、阿里云),但地址会变。必须设置定时任务(cron)更新Nginx配置并reload。如果漏更新,用户可能无法访问至返回403。
  • 忽略IPv6:如果CDN支持IPv6回源,务必在allow中添加IPv6段,否则IPv6回源会被deny all拦掉。
  • SSL证书问题:源站如果使用自签名证书或与CDN域名不同的证书,当客户端直接访问IP时会看到证书警告;更重要的是,公网扫描工具会通过证书的Subject CN或SAN字段关联到源站IP。建议源站只使用CDN颁发或信任的证书,且回源协议使用HTTPS。

结语

Nginx反向代理配合CDN隐藏源站IP是一个系统工程,远不止配置一个proxy_pass。从IP白名单、真实IP提取、SSL客户端验证,到屏蔽服务器头和证书管理,每一层都在削弱攻击者接近真实服务器的能力。同时要记得:没有绝对的安全,CDN节点IP列表的动态维护、定期扫描验证、防火墙多重防御才是最稳妥的做法。希望本文的配置思路能帮助你在生产环境中建立可靠的CDN回源防护体系。

延伸阅读