最近排查了一个和 CDN 回源 Header 有关的问题:源站经常会依赖 CDN 写入的 IP / GeoIP Header 来判断用户真实 IP 或国家地区,例如 Cloudflare 的 CF-Connecting-IP、CF-IPCountry,以及 AWS CloudFront 的 CloudFront-Viewer-Address、CloudFront-Viewer-Country。
源站使用这些字段前,需要确认请求来自可信的 CDN 回源链路。客户端直连源站时也能携带同名 Header,字段名本身不能证明来源。
本文先列出 CloudFront 和 Cloudflare 的 IP / GeoIP 字段,再以 Cloudflare 为例说明同名 Header 的处理、直连绕过和源站认证。
CloudFront 的 IP / GeoIP 字段
AWS CloudFront 官方支持在回源请求中添加 Viewer 信息 Header。和 IP / 地理位置相关的主要是:
CloudFront-Viewer-Address
CloudFront-Viewer-ASN
CloudFront-Viewer-Country
CloudFront-Viewer-City
CloudFront-Viewer-Country-Name
CloudFront-Viewer-Country-Region
CloudFront-Viewer-Country-Region-Name
CloudFront-Viewer-Latitude
CloudFront-Viewer-Longitude
CloudFront-Viewer-Metro-Code
CloudFront-Viewer-Postal-Code
CloudFront-Viewer-Time-Zone
官方解释很直接:这些值由 CloudFront 根据访问者 IP 计算后加到转发给 Origin 的请求里,Origin 不需要自己做 IP 库查询。
几个常用字段:
CloudFront-Viewer-Address:访问者 IP 和源端口,例如198.51.100.10:46532CloudFront-Viewer-Country:两位国家码,例如US、JPCloudFront-Viewer-City:城市名,部分 IP 没有对应数据CloudFront-Viewer-ASN:访问者所在自治系统 ASN
用法上主要有两类:
- 只给源站做日志、统计、风控参考:放到 Origin Request Policy,不要进缓存 key。
- 如果响应内容会根据国家地区变化:放到 Cache Policy,让它进入缓存 key,避免不同地区用户命中同一份缓存。
AWS 官方文档:
Cloudflare 对应的 Header
Cloudflare 常见的是:
CF-Connecting-IP
CF-IPCountry
X-Forwarded-For
其中:
CF-Connecting-IP:Cloudflare 认为的访问者真实 IPCF-IPCountry:访问者国家,两位国家码;特殊值XX表示无国家数据,T1表示 TorX-Forwarded-For:代理链路上常见的客户端 IP 列表
Cloudflare 官方文档里说,CF-Connecting-IP 只会在 Cloudflare Edge 到 Origin 的流量中发送。CF-IPCountry 这类访问者位置信息,可以通过 Add visitor location headers Managed Transform 添加。
Cloudflare 官方文档:
- https://developers.cloudflare.com/fundamentals/reference/http-headers/
- https://developers.cloudflare.com/rules/transform/managed-transforms/reference/
以下测试区分经过 Cloudflare 代理和直连源站两条路径。
经过 Cloudflare:客户端自带的同名 Header
在本次测试中,经过 Cloudflare 代理后,源站收到的是边缘层生成的 IP / GeoIP 值。
比如用户请求时自己加:
CF-IPCountry: US
CF-Connecting-IP: 1.2.3.4
源站收到的值由 Cloudflare 根据连接信息和 IP 地理位置结果写入,未采用上述客户端自带值。
未开启位置 Header 回写的情况
假设 Cloudflare 没开 Add visitor location headers,用户在请求中加入:
CF-IPCountry: US
本次测试中,未开启回写时,源站也没有收到用户自带的 CF-IPCountry。
直连源站:同名 Header 可由客户端构造
主要风险来自绕过 Cloudflare 直连源站。
如果攻击者知道源站真实 IP,直接请求源站:
curl http://源站IP/ \
-H 'Host: example.com' \
-H 'CF-IPCountry: US' \
-H 'CF-Connecting-IP: 1.2.3.4'
这时候请求根本没有经过 Cloudflare。源站看到的 Header 就只是普通 HTTP Header。如果后端网关或应用没有判断请求来源,就有可能把这些伪造的 CF-* 当真。
Cloudflare 官方也明确提醒过:如果有人发现了源站 IP,就可以直接给源站发请求,绕过 Cloudflare 的安全保护。官方建议阻止所有非 Cloudflare IP、非可信合作方或可信应用的流量。
官方文档:
限制源站入口
最基本的做法:源站防火墙、安全组、负载均衡器只允许 Cloudflare IP 段访问 80/443。
也就是:
允许 Cloudflare IP -> 源站
拒绝其他公网 IP -> 源站
这能解决大部分直连绕过问题。
但只做 IP allowlist 也有维护成本:Cloudflare IP 段可能更新,源站环境里也可能有其他旁路入口。因此还可以加一层 Cloudflare 的 Authenticated Origin Pulls。
Cloudflare 的签名 / 校验机制:Authenticated Origin Pulls
Cloudflare 的回源身份校验机制叫 Authenticated Origin Pulls,简称 AOP。它通过 mTLS 验证回源连接的客户端证书。
开启后,Cloudflare 回源时会带客户端证书,源站验证这个证书。验证通过,说明请求确实来自 Cloudflare 的回源链路。
官方文档:
AOP 有三种级别:
- Global:使用 Cloudflare 共享证书,只能证明“来自 Cloudflare 网络”。
- Zone-level:使用你上传的证书,可以证明“来自你的 zone 配置”。
- Per-hostname:按 hostname 配证书,粒度更细。
Global AOP 可以拦截普通直连攻击;Zone-level 或 Per-hostname 还能进一步确认请求来自自己的 Cloudflare 配置。
AOP 的配置边界
AOP 使用成熟的 mTLS 机制,实际风险主要来自配置错误。
客户端必须持有对应私钥才能完成证书认证。部署时需要检查以下配置风险:
- 源站没有真的强制校验客户端证书。
- 只在 Cloudflare 开了 AOP,但 Nginx / Ingress / LB 没配好。
- 使用 Global AOP,只证明来自 Cloudflare 网络,不证明来自你的 zone。
- 源站还有其他端口、其他域名、内网转发、旧 IP 可以绕过。
- 私钥或证书配置泄露。
部署时将回源认证与入口限制配合使用:
Cloudflare 代理
+ 源站只允许 Cloudflare IP
+ Authenticated Origin Pulls,优先 Zone-level / Per-hostname
+ 应用层只在确认来源可信后读取 CF-* Header
