别让 Cloudflare 成摆设:源站泄露、缓存误配与自查脚本实战
Cloudflare 安全漏洞分析|附源码
说明:本文面向安全研究、架构审计与防御加固场景,重点分析 Cloudflare 使用过程中常见的安全风险、配置漏洞与防护误区。文中“源码”部分提供的是本地可运行的安全检测与演示代码,用于帮助开发者理解风险原理、检查自身资产配置,不包含针对第三方目标的攻击利用代码。
一、前言
Cloudflare 是目前全球使用最广泛的 CDN、DNS、WAF 与边缘安全平台之一。大量网站会将域名解析托管到 Cloudflare,并借助其提供的 DDoS 防护、反向代理、缓存、TLS、访问控制、Bot 管理、Web Application Firewall 等能力来提升网站性能与安全性。
然而,在实际安全评估中,我们经常发现一个现象:很多企业或个人站点“接入了 Cloudflare”,但并不等于“已经安全”。Cloudflare 本身作为成熟平台,安全能力非常强,但最终防护效果高度依赖于使用者的配置方式、源站暴露情况、DNS 管理习惯、业务访问策略以及后端应用自身安全性。
换句话说,Cloudflare 更像是一层强大的安全边界,但如果边界配置不当,或者源站绕过了这层边界,攻击者依然可能直接访问真实服务器,从而绕过 CDN/WAF 的防护。
本文将从以下几个方面展开:
- Cloudflare 的基本防护模型;
- 常见安全风险与漏洞类型;
- 源站 IP 泄露问题分析;
- WAF 与缓存配置误区;
- SSL/TLS 配置风险;
- 访问控制与 Zero Trust 使用建议;
- 安全检查脚本源码示例;
- 加固建议与安全清单。
二、Cloudflare 的安全模型概述
Cloudflare 的核心工作方式是反向代理。
正常情况下,用户访问网站时的链路如下:
用户浏览器
↓
Cloudflare 边缘节点
↓
源站服务器
当域名开启 Cloudflare 代理后,公网 DNS 解析结果通常会指向 Cloudflare 的边缘节点 IP,而不是源站真实 IP。这样一来,请求会先到达 Cloudflare,由 Cloudflare 进行安全过滤、缓存处理、TLS 终止、访问控制等操作,然后再转发给源站服务器。
这种模式的安全优势包括:
- 隐藏源站真实 IP;
- 抵御大流量 DDoS 攻击;
- 使用 WAF 拦截常见 Web 攻击;
- 使用 Bot 管理识别异常请求;
- 支持 Rate Limiting 限速;
- 提供 TLS/HTTPS 能力;
- 通过 Access、Tunnel、Zero Trust 控制后台访问。
但该模型有一个非常关键的前提:
源站必须只允许 Cloudflare 访问,不能直接暴露给公网。
如果攻击者知道源站 IP,并且源站服务器允许任意公网 IP 直接访问,那么攻击者可以绕过 Cloudflare,直接攻击后端服务。
三、常见 Cloudflare 使用风险
1. 源站 IP 泄露
源站 IP 泄露是 Cloudflare 防护体系中最常见、也是影响最大的风险之一。
常见泄露途径包括:
- 历史 DNS 记录暴露;
- 子域名未接入 Cloudflare;
- 邮件服务暴露真实 IP;
- 源站主动发起请求泄露地址;
- SSL 证书透明日志暴露子域名;
- GitHub、配置文件、日志中泄露 IP;
- 旧系统迁移时遗留解析记录;
- 直接访问源站 IP 能返回站点内容。
例如,主站 www.example.com 已经接入 Cloudflare,但 api.example.com、origin.example.com、dev.example.com 等子域名仍然直接指向源站或同一服务器。一旦攻击者发现这些记录,就可能推测出真实 IP。
更严重的是,如果源站服务器对 Host 请求头没有限制,攻击者甚至可以通过源站 IP 加上正确的 Host 头访问完整业务站点。
2. DNS 配置不一致
Cloudflare 的 DNS 记录有两种典型状态:
- 橙色云朵:开启代理;
- 灰色云朵:仅 DNS 解析,不经过 Cloudflare 代理。
很多用户会误以为“域名放在 Cloudflare 就安全了”,但实际上只有开启代理的记录才会经过 Cloudflare 防护。
如果某些 A 记录、AAAA 记录、CNAME 记录处于灰色云朵状态,那么这些服务仍然可能直接暴露真实地址。
常见误区包括:
- 主站开启代理,后台管理域名未开启;
- API 子域名未开启代理;
- 上传服务、图片服务直接暴露;
- 测试环境解析到生产服务器;
- IPv4 开启代理,IPv6 忘记处理。
3. 源站防火墙未限制 Cloudflare IP
正确配置下,源站服务器应该只接受来自 Cloudflare 官方 IP 段的 HTTP/HTTPS 请求。
如果源站安全组、防火墙、Nginx、Apache 没有限制来源 IP,那么即使域名走了 Cloudflare,攻击者仍然可以尝试直接连接源站。
这种问题尤其常见于云服务器安全组配置中。例如:
- 80/443 对全网开放;
- 管理端口直接暴露;
- 仅依赖 Cloudflare WAF,不配置源站访问控制;
- 源站有多个公网 IP,其中一个未被保护。
4. SSL/TLS 模式配置不安全
Cloudflare 提供多种 SSL/TLS 模式,包括:
- Off;
- Flexible;
- Full;
- Full Strict。
其中比较容易出问题的是 Flexible 模式。
在 Flexible 模式下,用户到 Cloudflare 是 HTTPS,但 Cloudflare 到源站可能是 HTTP。这会导致边缘到源站之间的链路没有端到端加密。如果源站链路经过不可信网络,可能存在中间人风险。
推荐使用:
Full (Strict)
并在源站部署有效证书,可以使用:
- 公信 CA 证书;
- Cloudflare Origin Certificate;
- 自动化 ACME 证书。
5. 缓存规则配置不当
Cloudflare 的缓存能力非常强,但错误的缓存配置可能导致敏感信息泄露。
常见风险包括:
- 将带有用户身份信息的页面缓存;
- API 响应被错误缓存;
- 私有文件被缓存;
- 后台页面被缓存;
- 忽略 Cookie 或 Authorization 头;
- Cache Everything 规则使用过度。
例如,某些站点为了提升速度设置了“Cache Everything”,但没有排除 /admin、/user、/api 等路径,可能导致用户 A 的页面被缓存后返回给用户 B。
安全建议:
- 登录态页面不要缓存;
- 包含 Authorization、Cookie 的响应谨慎缓存;
- 后端设置正确的 Cache-Control;
- 对管理后台路径设置 Bypass Cache;
- 对动态 API 明确禁止共享缓存。
6. WAF 规则过于宽松
Cloudflare WAF 可以拦截 SQL 注入、XSS、RCE、文件包含等攻击,但它不是万能的。
常见问题包括:
- 只开启默认规则,没有针对业务定制;
- 高风险路径没有额外规则;
- 误将大量规则设置为 Log 而非 Block;
- 对 API 缺乏速率限制;
- 对登录接口缺少暴力破解防护;
- 未启用 Bot Fight Mode 或 Turnstile。
WAF 更适合作为“纵深防御”的一层,而不是替代应用自身的安全编码。
7. 后台管理入口暴露
很多网站后台管理地址如:
/admin
/wp-admin
/login
/manage
/dashboard
即使接入 Cloudflare,如果没有额外访问控制,攻击者仍然可以对这些路径进行爆破、撞库、弱口令尝试或漏洞扫描。
推荐做法:
- 后台入口接入 Cloudflare Access;
- 限制国家/地区;
- 限制 IP 段;
- 启用多因素认证;
- 使用 Zero Trust 策略;
- 对登录接口设置速率限制;
- 对异常 User-Agent 或自动化请求进行挑战。
四、典型风险场景分析
场景一:源站 IP 暴露导致绕过 WAF
假设某网站:
www.example.com -> Cloudflare
源站 IP -> 203.0.113.10
用户正常访问时,请求会先进入 Cloudflare。若攻击者不知道源站 IP,攻击流量会被 Cloudflare 拦截。
但如果攻击者通过历史 DNS 或其他渠道发现源站 IP,并且源站允许公网直接访问,那么实际链路变成:
攻击者
↓
203.0.113.10
↓
源站应用
此时 Cloudflare 完全不在请求链路中,WAF、DDoS 防护、Bot 检测全部失效。
防护核心:
- 源站防火墙只允许 Cloudflare IP;
- 源站应用校验请求来源;
- 使用 Cloudflare Tunnel 隐藏源站;
- 后台服务不开放公网入口。
场景二:缓存配置错误导致用户数据泄露
某站点设置:
Cache Level: Cache Everything
Edge Cache TTL: 1 hour
同时没有排除:
/user/profile
/account
/api/userinfo
当用户 A 登录后访问 /user/profile,页面可能被 Cloudflare 缓存。如果缓存键没有正确区分 Cookie、Authorization 或用户身份,用户 B 后续访问时可能获得用户 A 的页面内容。
这类问题在动态站点、单页应用、API 网关中较常见。
防护方法:
- 后端返回
Cache-Control: private, no-store; - 对用户中心、订单、账户路径设置绕过缓存;
- 不对含登录态响应启用公共缓存;
- 定期检查缓存规则;
- 使用测试账号验证是否存在交叉缓存。
场景三:Flexible SSL 导致链路降级
如果设置为 Flexible SSL:
用户 -> HTTPS -> Cloudflare -> HTTP -> 源站
用户浏览器看到的是 HTTPS,但 Cloudflare 到源站不是 HTTPS。对于安全要求较高的业务,这不是理想状态。
可能风险:
- 源站链路被监听;
- 内部网络被劫持;
- 请求参数泄露;
- Cookie 在源站链路中明文传输;
- 误判整体站点已经端到端加密。
推荐配置:
用户 -> HTTPS -> Cloudflare -> HTTPS -> 源站
并启用:
SSL/TLS Mode: Full Strict
五、安全检测脚本源码
下面提供一个 Python 脚本,用于对指定域名进行基础安全配置检查。它不会进行攻击行为,只做 DNS 解析、HTTP 响应头检查、HTTPS 检查和缓存相关提示,适合用于自查。
1. 功能说明
该脚本支持:
- 查询域名解析结果;
- 判断解析 IP 是否可能属于 Cloudflare;
- 检查 HTTP 安全响应头;
- 检查缓存相关响应头;
- 检查是否启用 HTTPS;
- 输出基础风险提示。
2. Python 源码
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Cloudflare 安全配置自查脚本
用途:
1. 检查域名解析结果;
2. 判断是否可能经过 Cloudflare;
3. 检查 HTTPS 与常见安全响应头;
4. 检查缓存相关响应头;
5. 输出安全建议。
注意:
该脚本仅用于检测你有权限管理的域名。
"""
import socket
import ssl
import sys
import ipaddress
import urllib.request
from urllib.error import URLError, HTTPError
CLOUDFLARE_IPV4_RANGES = [
"173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"141.101.64.0/18",
"108.162.192.0/18",
"190.93.240.0/20",
"188.114.96.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"162.158.0.0/15",
"104.16.0.0/13",
"104.24.0.0/14",
"172.64.0.0/13",
"131.0.72.0/22",
]
SECURITY_HEADERS = [
"strict-transport-security",
"content-security-policy",
"x-content-type-options",
"x-frame-options",
"referrer-policy",
"permissions-policy",
]
CACHE_HEADERS = [
"cache-control",
"cf-cache-status",
"age",
"etag",
"expires",
]
def resolve_domain(domain):
"""解析域名 IP"""
try:
infos = socket.getaddrinfo(domain, None)
ips = sorted(set([info[4][0] for info in infos]))
return ips
except socket.gaierror:
return []
def is_cloudflare_ip(ip):
"""判断 IP 是否属于 Cloudflare IPv4 段"""
try:
ip_obj = ipaddress.ip_address(ip)
if ip_obj.version != 4:
return False
for cidr in CLOUDFLARE_IPV4_RANGES:
if ip_obj in ipaddress.ip_network(cidr):
return True
return False
except ValueError:
return False
def fetch_headers(url, timeout=10):
"""获取 HTTP 响应头"""
req = urllib.request.Request(
url,
headers={
"User-Agent": "CF-Security-Checker/1.0"
}
)
try:
with urllib.request.urlopen(req, timeout=timeout) as resp:
headers = dict(resp.headers)
status = resp.status
return status, {k.lower(): v for k, v in headers.items()}, None
except HTTPError as e:
headers = dict(e.headers)
return e.code, {k.lower(): v for k, v in headers.items()}, None
except URLError as e:
return None, {}, str(e)
except Exception as e:
return None, {}, str(e)
def check_https(domain, timeout=10):
"""检查 HTTPS 握手是否正常"""
context = ssl.create_default_context()
try:
with socket.create_connection((domain, 443), timeout=timeout) as sock:
with context.wrap_socket(sock, server_hostname=domain) as ssock:
cert = ssock.getpeercert()
tls_version = ssock.version()
return True, tls_version, cert
except Exception as e:
return False, None, str(e)
def print_section(title):
print("\n" + "=" * 60)
print(title)
print("=" * 60)
def main():
if len(sys.argv) != 2:
print("用法:python3 cf_security_check.py example.com")
sys.exit(1)
domain = sys.argv[1].strip()
print_section("1. DNS 解析检查")
ips = resolve_domain(domain)
if not ips:
print("[!] 未解析到 IP,请检查域名是否正确。")
else:
for ip in ips:
cf = is_cloudflare_ip(ip)
mark = "可能属于 Cloudflare" if cf else "不在内置 Cloudflare IPv4 段"
print(f"- {ip}:{mark}")
if all(is_cloudflare_ip(ip) for ip in ips if ":" not in ip):
print("[+] IPv4 解析结果看起来经过 Cloudflare。")
else:
print("[!] 存在非 Cloudflare IPv4,需确认是否为源站暴露或灰云记录。")
print_section("2. HTTPS 检查")
ok, tls_version, cert_info = check_https(domain)
if ok:
print(f"[+] HTTPS 握手正常,TLS 版本:{tls_version}")
else:
print(f"[!] HTTPS 检查失败:{cert_info}")
print_section("3. HTTP 响应头检查")
url = f"https://{domain}/"
status, headers, error = fetch_headers(url)
if error:
print(f"[!] 请求失败:{error}")
else:
print(f"[+] 状态码:{status}")
print("\n安全响应头:")
for h in SECURITY_HEADERS:
if h in headers:
print(f"[+] {h}: {headers[h]}")
else:
print(f"[!] 缺少 {h}")
print("\n缓存相关响应头:")
for h in CACHE_HEADERS:
if h in headers:
print(f"- {h}: {headers[h]}")
server = headers.get("server")
if server:
print(f"\nServer: {server}")
cf_ray = headers.get("cf-ray")
if cf_ray:
print("[+] 检测到 cf-ray,说明响应很可能经过 Cloudflare。")
else:
print("[!] 未检测到 cf-ray,需确认是否经过 Cloudflare 或被隐藏。")
print_section("4. 安全建议")
print("- 确认所有公网业务域名均开启 Cloudflare 代理。")
print("- 源站防火墙仅允许 Cloudflare IP 段访问 80/443。")
print("- SSL/TLS 建议使用 Full Strict 模式。")
print("- 动态页面、用户中心、后台管理路径不要错误缓存。")
print("- 后台入口建议接入 Cloudflare Access 或 Zero Trust。")
print("- 登录、注册、短信、搜索等接口建议设置速率限制。")
print("- 定期审计 DNS 记录、证书透明日志和历史解析记录。")
if __name__ == "__main__":
main()
3. 使用方式
保存为:
cf_security_check.py
运行:
python3 cf_security_check.py example.com
输出示例:
============================================================
1. DNS 解析检查
============================================================
- 104.21.x.x:可能属于 Cloudflare
- 172.67.x.x:可能属于 Cloudflare
[+] IPv4 解析结果看起来经过 Cloudflare。
============================================================
2. HTTPS 检查
============================================================
[+] HTTPS 握手正常,TLS 版本:TLSv1.3
需要注意的是,该脚本只做基础检查,不能替代完整安全审计。Cloudflare 官方 IP 段也可能更新,生产环境中建议从 Cloudflare 官方文档或 API 动态同步最新 IP 段。
六、源站防护配置示例
1. Nginx 限制访问来源示例
如果源站前面接入 Cloudflare,可以在 Nginx 层限制只有 Cloudflare IP 可以访问。
示例片段如下:
server {
listen 80;
server_name example.com www.example.com;
# 示例:允许 Cloudflare IP 段
allow 173.245.48.0/20;
allow 103.21.244.0/22;
allow 103.22.200.0/22;
allow 103.31.4.0/22;
allow 141.101.64.0/18;
allow 108.162.192.0/18;
allow 190.93.240.0/20;
allow 188.114.96.0/20;
allow 197.234.240.0/22;
allow 198.41.128.0/17;
allow 162.158.0.0/15;
allow 104.16.0.0/13;
allow 104.24.0.0/14;
allow 172.64.0.0/13;
allow 131.0.72.0/22;
# 拒绝其他来源
deny all;
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $http_cf_connecting_ip;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
生产环境应同时加入 Cloudflare IPv6 段,并通过自动化方式定期同步官方 IP 列表。
2. 真实客户端 IP 获取
接入 Cloudflare 后,源站看到的直接连接 IP 通常是 Cloudflare 节点,而不是用户真实 IP。Cloudflare 会通过请求头传递真实客户端 IP,例如:
CF-Connecting-IP
Nginx 可配置:
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 131.0.72.0/22;
real_ip_header CF-Connecting-IP;
但要注意,只有在你已经限制源站仅允许 Cloudflare 访问的前提下,才应信任 CF-Connecting-IP。否则攻击者可以直接访问源站并伪造该请求头。
七、Cloudflare WAF 加固建议
1. 开启托管规则集
建议启用 Cloudflare Managed Rules,包括:
- Cloudflare Managed Ruleset;
- OWASP Core Ruleset;
- WordPress/Joomla/Drupal 等 CMS 专项规则;
- 已知 CVE 防护规则。
规则动作可根据业务情况设置为:
Log -> Challenge -> Block
上线初期建议先观察日志,避免误杀核心业务。
2. 对高风险路径添加自定义规则
例如后台路径:
/admin
/wp-admin
/manage
/dashboard
可以添加规则:
- 非指定国家访问则挑战;
- 非办公 IP 访问则阻断;
- 未通过 Access 认证则拒绝;
- 异常 User-Agent 挑战;
- 登录接口超过频率限制则封禁。
3. API 接口速率限制
对以下接口尤其需要限速:
/login/register/password/reset/api/send_sms/api/search/api/comment/api/upload
建议策略:
同一 IP 1 分钟内超过 N 次请求触发 Managed Challenge 或 Block
对于登录类接口,还应结合账号维度、设备指纹、验证码、多因素认证进行防护。
八、缓存安全最佳实践
缓存策略应遵循一个原则:
默认不缓存敏感动态内容,只缓存明确安全的静态资源。
推荐缓存的内容包括:
/static/*
/assets/*
/images/*
/css/*
/js/*
谨慎或禁止缓存的内容包括:
/admin/*
/user/*
/account/*
/order/*
/cart/*
/api/*
/login
/logout
后端响应头建议:
Cache-Control: no-store
用于极敏感内容,例如账户、订单、支付、后台页面。
对于普通动态页面:
Cache-Control: private, no-cache
对于静态资源:
Cache-Control: public, max-age=31536000, immutable
九、SSL/TLS 安全建议
建议配置如下:
- SSL/TLS 模式选择
Full Strict; - 源站部署有效证书;
- 开启 Always Use HTTPS;
- 开启 HTTP Strict Transport Security;
- 最低 TLS 版本建议 TLS 1.2 或更高;
- 关闭过时加密协议;
- 对敏感业务启用 mTLS 或 Cloudflare Access;
- 使用 Origin Certificate 时注意证书有效期管理。
HSTS 示例:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
但启用 includeSubDomains 和 preload 前必须确认所有子域均支持 HTTPS,否则可能造成业务不可访问。
十、安全审计清单
下面是一份实用的 Cloudflare 安全审计清单。
DNS 与源站
- [ ] 所有公网业务域名是否开启代理;
- [ ] 是否存在灰云 A/AAAA/CNAME 记录;
- [ ] 是否存在历史 DNS 泄露;
- [ ] 是否存在未保护子域名;
- [ ] 源站 80/443 是否只允许 Cloudflare IP;
- [ ] IPv6 是否同样受控;
- [ ] 是否使用 Cloudflare Tunnel 隐藏源站。
WAF 与访问控制
- [ ] 是否启用托管 WAF 规则;
- [ ] 是否启用 OWASP 规则集;
- [ ] 后台路径是否有额外保护;
- [ ] 登录接口是否有限速;
- [ ] 是否启用 Bot 防护;
- [ ] 是否接入 Turnstile;
- [ ] 是否配置 Cloudflare Access。
TLS 与证书
- [ ] SSL/TLS 是否为 Full Strict;
- [ ] 源站证书是否有效;
- [ ] 是否强制 HTTPS;
- [ ] 是否启用 HSTS;
- [ ] 是否禁用旧 TLS 协议。
缓存与响应头
- [ ] 动态页面是否绕过缓存;
- [ ] 用户数据接口是否禁止公共缓存;
- [ ] 是否设置合理的 Cache-Control;
- [ ] 是否配置 CSP;
- [ ] 是否设置 X-Content-Type-Options;
- [ ] 是否设置 Referrer-Policy;
- [ ] 是否设置 Permissions-Policy。
十一、总结
Cloudflare 能显著提升网站的安全性与可用性,但它不是“接入即安全”的万能方案。真正安全的 Cloudflare 架构应该满足以下条件:
- 域名请求必须经过 Cloudflare;
- 源站不能被公网直接访问;
- WAF、Bot、Rate Limiting 需要按业务定制;
- 动态内容缓存必须谨慎;
- TLS 应实现端到端加密;
- 后台与敏感接口应使用 Zero Trust 或 Access 保护;
- 应定期审计 DNS、证书、日志与配置变化。
从防御视角看,Cloudflare 的价值不仅在于“隐藏源站”或“抵御攻击”,更在于它提供了一套边缘安全控制面。只有将 Cloudflare 与源站防火墙、应用安全编码、身份认证、日志监控、漏洞管理结合起来,才能形成真正有效的纵深防御体系。
本文提供的检测脚本可以作为日常安全巡检的起点,用于发现基础配置问题。对于生产环境,还应结合自动化资产扫描、Cloudflare API、SIEM 日志分析和人工安全审计,持续提升整体安全水位。