1. 为什么需要获取CDN背后的真实客户端IP
当你的网站接入了CDN服务后,所有访问请求都会先经过CDN节点,再由CDN节点回源到你的服务器。这种情况下,Nginx日志中记录的IP地址全都是CDN节点的IP,而不是真实的客户端IP。这就带来了一个严重的安全隐患:当需要封禁恶意请求时,你只能封禁CDN节点的IP,这会导致所有经过该CDN节点的正常用户也被误伤。
我最近就遇到了这样的问题:一个恶意爬虫通过CDN不断扫描我们的API接口,但由于只能看到CDN的IP,封禁操作变得束手束脚。经过一番排查,终于找到了解决方案。下面我就详细分享这个问题的完整处理过程。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. CDN传递真实IP的机制解析
2.1 X-Forwarded-For头部的工作机制
大多数CDN服务商都会在请求头中添加X-Forwarded-For(XFF)字段来传递客户端真实IP。这个字段的值是一个IP地址链,格式如下:
code复制X-Forwarded-For: 客户端IP, 代理服务器1IP, 代理服务器2IP,...
例如,当请求经过多层代理时:
- 客户端(1.1.1.1) → CDN边缘节点(2.2.2.2)
- XFF: 1.1.1.1
- CDN边缘节点 → CDN中间节点(3.3.3.3)
- XFF: 1.1.1.1, 2.2.2.2
- CDN中间节点 → 源站服务器(4.4.4.4)
- XFF: 1.1.1.1, 2.2.2.2, 3.3.3.3
2.2 常见CDN服务商的特殊头部
不同CDN服务商可能使用不同的头部传递真实IP:
- 阿里云CDN:Ali-CDN-Real-IP
- 腾讯云CDN:X-Real-IP
- Cloudflare:CF-Connecting-IP
- AWS CloudFront:True-Client-IP
3. Nginx配置获取真实IP的最佳实践
3.1 基础配置方案
在Nginx的http或server块中添加以下配置:
nginx复制set_real_ip_from 0.0.0.0/0; # 信任所有上游代理(生产环境应指定CDN IP段)
real_ip_header X-Forwarded-For;
real_ip_recursive on;
这个配置的工作原理:
set_real_ip_from定义可信的代理服务器IP范围real_ip_header指定从哪个头部获取真实IPreal_ip_recursive启用递归查找,从右向左遍历XFF链,跳过可信IP
3.2 生产环境安全配置
更安全的做法是只信任你的CDN提供商的IP段:
nginx复制# 阿里云CDN IP段示例
set_real_ip_from 47.99.0.0/16;
set_real_ip_from 47.98.0.0/15;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
重要提示:CDN的IP段可能会变动,建议定期从CDN服务商处获取最新IP列表
3.3 多CDN服务商混合配置
如果你的网站接入了多个CDN服务,可以这样配置:
nginx复制# 阿里云CDN
set_real_ip_from 47.99.0.0/16;
# 腾讯云CDN
set_real_ip_from 58.250.143.0/24;
# Cloudflare
set_real_ip_from 103.21.244.0/22;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
4. 验证真实IP获取是否成功
4.1 测试方法
在Nginx配置中添加一个测试location:
nginx复制location /test-ip {
return 200 "$remote_addr\n";
}
然后通过curl测试:
bash复制curl -H "X-Forwarded-For: 1.1.1.1, 2.2.2.2" http://yourdomain.com/test-ip
正确配置应该返回:1.1.1.1
4.2 日志格式修改
修改Nginx日志格式以记录真实IP和XFF头:
nginx复制log_format main '$remote_addr - $realip_remote_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'xff:"$http_x_forwarded_for"';
5. 基于真实IP的访问控制
5.1 封禁单个IP
nginx复制location / {
deny 1.1.1.1;
allow all;
# 其他配置...
}
5.2 封禁IP段
nginx复制geo $blocked_ip {
default 0;
1.1.1.0/24 1;
2.2.2.2/32 1;
}
server {
if ($blocked_ip) {
return 403;
}
# 其他配置...
}
5.3 动态封禁方案
结合fail2ban实现自动封禁:
- 首先确保Nginx记录了真实IP
- 配置fail2ban监控Nginx日志
- 设置封禁规则,例如:
ini复制[nginx-badbots]
enabled = true
port = http,https
filter = nginx-badbots
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 3600
bantime = 86400
6. 常见问题与解决方案
6.1 获取不到真实IP的可能原因
-
CDN未正确配置XFF头
- 解决方案:检查CDN配置,确保开启了"回源携带客户端IP"选项
-
Nginx配置错误
- 检查项:real_ip_header设置是否正确,set_real_ip_from是否包含CDN IP
-
请求经过了多层代理
- 解决方案:启用real_ip_recursive并确保所有代理IP都在信任列表中
6.2 安全风险防范
-
XFF头伪造风险
- 只信任已知的CDN IP段
- 使用$realip_remote_addr而不是直接解析XFF头
-
CDN IP段变更
- 建议每月检查一次CDN服务商公布的IP段
- 可以使用自动化脚本更新Nginx配置
6.3 性能优化建议
- 避免使用0.0.0.0/0这样的宽泛信任范围
- 对频繁访问的恶意IP,考虑使用Nginx的map指令进行内存级过滤
- 大量封禁规则时,使用geo模块比多个deny指令更高效
7. 高级应用场景
7.1 结合GeoIP限制地区访问
nginx复制geo $allowed_country {
default no;
CN yes;
US yes;
}
map $realip_remote_addr $blocked_ip {
include /path/to/ip-blacklist.conf;
default 0;
}
server {
if ($allowed_country = no) {
return 403;
}
if ($blocked_ip) {
return 403;
}
# 其他配置...
}
7.2 限流配置示例
基于真实IP的请求限流:
nginx复制limit_req_zone $realip_remote_addr zone=api_limit:10m rate=10r/s;
location /api/ {
limit_req zone=api_limit burst=20 nodelay;
# 其他配置...
}
7.3 动态黑名单管理
使用Nginx+Lua实现动态黑名单:
nginx复制lua_shared_dict ip_blacklist 10m;
server {
location / {
access_by_lua_block {
local blacklist = ngx.shared.ip_blacklist
local real_ip = ngx.var.realip_remote_addr
if blacklist:get(real_ip) then
ngx.exit(403)
end
}
# 其他配置...
}
location /admin/blacklist {
content_by_lua_block {
-- 实现添加/删除黑名单IP的API
}
}
}
8. 实际案例:防御CC攻击
最近我们遭遇了一次CC攻击,攻击者通过CDN不断发起请求。通过以下配置成功防御:
- 首先确保获取到真实IP
- 分析日志找到攻击IP特征
- 实施临时封禁:
nginx复制geo $cc_attack {
default 0;
include /etc/nginx/conf.d/attack-ips.conf;
}
server {
if ($cc_attack) {
return 444; # 直接关闭连接
}
# 其他配置...
}
其中attack-ips.conf内容格式:
code复制1.1.1.1/32 1;
2.2.2.0/24 1;
- 设置自动化脚本,每小时分析日志更新attack-ips.conf
9. 性能影响评估
获取真实IP的操作对Nginx性能影响很小,主要考虑点:
- real_ip_recursive开启时会有额外的IP解析开销
- 大量set_real_ip_from指令会增加配置复杂度
- 建议在生产环境进行压力测试
测试方法:
bash复制ab -c 100 -n 10000 http://yourdomain.com/test-ip
10. 其他Web服务器的配置参考
虽然本文主要讲Nginx,但其他Web服务器也有类似功能:
10.1 Apache配置
apache复制RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 2.2.2.2/32
10.2 Tomcat配置
在server.xml中添加:
xml复制<Valve className="org.apache.catalina.valves.RemoteIpValve"
remoteIpHeader="x-forwarded-for"
internalProxies="2\.2\.2\.2" />
11. 监控与告警建议
- 监控被封禁IP的数量变化
- 设置异常流量告警
- 定期审计封禁列表,避免误封
示例Zabbix监控项:
code复制nginx.http.status[403]
nginx.http.status[444]
12. 最佳实践总结
- 永远不要信任未经验证的XFF头
- 定期更新CDN IP段列表
- 实施分层防御策略
- 记录完整的访问日志以备审计
- 考虑使用WAF作为额外防护层
配置完成后,建议进行完整的渗透测试,确保安全防护措施不会引入新的漏洞。在实际运维中,我发现很多安全问题都源于配置不当,因此定期审查Nginx配置是非常必要的习惯。
