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响应头:
Server、X-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证书、应用层行为推测源站。以下策略可以进一步加固。
屏蔽服务器信息
在http、server或location块中加入:
server_tokens off;nproxy_hide_header X-Powered-By;nproxy_hide_header X-AspNet-Version;n# 移除Nginx版本号,同时隐藏后端返回的敏感头
同时确保add_header不要把内部IP暴露在Location或Access-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方法和路径
大部分回源请求只需要GET、HEAD、POST。在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回源防护体系。
延伸阅读
