Cloudflare 不是保险箱:源站暴露、缓存误配与防护实战源码
Cloudflare 安全漏洞分析|附源码
声明:本文面向安全研究、企业防护与工程实践,重点分析 Cloudflare 使用过程中常见的安全风险、配置误区与防御方案。文中源码仅用于本地实验环境、教学演示和安全加固,不包含针对真实第三方目标的攻击利用代码。请勿在未授权环境中进行扫描、测试或攻击行为。
一、引言
Cloudflare 是目前全球使用非常广泛的 CDN、DNS、WAF、DDoS 防护与边缘计算平台。很多网站接入 Cloudflare 后,可以获得以下能力:
- 隐藏源站真实 IP;
- 缓解 DDoS 攻击;
- 使用 WAF 阻断常见 Web 攻击;
- 通过 CDN 缓存提升访问速度;
- 使用 SSL/TLS 加密传输;
- 通过 Workers、Rules、Turnstile 等增强业务能力。
然而,很多企业在接入 Cloudflare 后,会产生一种误解:
“只要接入 Cloudflare,网站就安全了。”
实际上,Cloudflare 是安全体系中的重要一环,但不是万能防护层。
如果源站暴露、DNS 配置不当、缓存规则错误、WAF 策略过宽、回源策略缺少校验,攻击者依然可能绕过 Cloudflare 直接攻击源站,或利用业务自身逻辑缺陷造成安全问题。
本文将从以下几个方面进行分析:
- Cloudflare 常见安全风险类型;
- 源站 IP 暴露风险;
- DNS 与子域名配置问题;
- 缓存投毒与敏感信息缓存;
- WAF 绕过与安全规则误区;
- SSL/TLS 配置风险;
- Cloudflare Workers 安全注意事项;
- 本地实验源码与检测脚本;
- 企业级防护建议。
二、Cloudflare 的安全边界
在分析漏洞之前,需要先明确 Cloudflare 的安全边界。
Cloudflare 位于用户与源站之间,典型访问链路如下:
用户浏览器
↓
Cloudflare 边缘节点
↓
企业源站服务器
在这个架构中,Cloudflare 可以保护以下层面:
- DNS 解析隐藏源站;
- CDN 缓存静态资源;
- WAF 过滤恶意请求;
- Rate Limit 限制异常流量;
- DDoS 防护;
- TLS 证书托管;
- Bot 管理;
- 边缘访问控制。
但是,Cloudflare 不能天然解决以下问题:
- 应用代码中的 SQL 注入、XSS、SSRF;
- 后台弱口令;
- 源站端口暴露;
- 子域名解析错误;
- API 鉴权逻辑缺陷;
- 私有文件被错误缓存;
- 服务器自身漏洞;
- 错误的访问控制策略。
因此,Cloudflare 应当被视为“增强防护层”,而不是“替代安全开发和服务器加固的万能方案”。
三、风险一:源站真实 IP 暴露
1. 风险说明
很多网站接入 Cloudflare 的核心目的之一,是隐藏源站真实 IP。
如果攻击者获得源站 IP,就可以绕过 Cloudflare,直接访问源站服务器。
一旦源站允许公网直接访问,就可能导致:
- Cloudflare WAF 被绕过;
- DDoS 流量直接打到源站;
- 暴露管理端口,如 SSH、Redis、MySQL、RDP;
- 源站证书、服务指纹泄露;
- 真实基础设施被定位。
2. 常见暴露原因
源站 IP 暴露通常不是 Cloudflare 本身漏洞,而是配置或运维问题:
1)历史 DNS 记录泄露
网站接入 Cloudflare 前,可能曾经直接解析到源站 IP。
历史 DNS 数据可能被第三方搜索引擎、安全平台或被动 DNS 系统记录。
2)子域名未接入 Cloudflare
例如:
www.example.com → Cloudflare
api.example.com → Cloudflare
test.example.com → 真实源站 IP
admin.example.com → 真实源站 IP
攻击者可能通过子域名发现源站所在 IP 段。
3)邮件服务器暴露
如果网站和邮件服务部署在同一台服务器上,MX、SPF、邮件头可能泄露源站 IP。
4)源站主动请求外部资源
应用服务器向第三方服务发起请求时,可能暴露出口 IP。
5)未限制源站访问来源
即使网站接入 Cloudflare,如果源站防火墙仍允许所有 IP 访问 80/443,也会造成绕过风险。
四、风险二:DNS 配置错误
Cloudflare DNS 中的记录通常有两种状态:
- Proxied:橙色云朵,流量经过 Cloudflare;
- DNS only:灰色云朵,只做 DNS 解析,不经过 Cloudflare。
如果敏感业务记录被设置为 DNS only,就会直接暴露真实服务器地址。
示例风险配置
A example.com Proxied
A www.example.com Proxied
A admin.example.com DNS only
A api.example.com DNS only
其中 admin.example.com 和 api.example.com 就可能绕过 Cloudflare 防护。
防护建议
- 所有 Web 业务域名尽量启用 Proxied;
- 非 Web 服务单独部署,不与 Web 源站共用 IP;
- 对管理后台使用 Zero Trust、VPN 或 IP 白名单;
- 定期检查 DNS 记录;
- 删除废弃子域名;
- 避免将测试环境暴露到公网。
五、风险三:缓存投毒与敏感信息缓存
Cloudflare 的缓存能力非常强,但缓存规则配置错误时,也可能引发严重安全问题。
1. 敏感页面被缓存
如果登录后页面、用户资料、订单详情、API 响应被错误缓存,则可能出现:
- A 用户访问后,页面被缓存;
- B 用户访问相同 URL;
- B 看到 A 的敏感信息。
常见风险路径包括:
/user/profile
/order/detail?id=1001
/api/user/info
/account/settings
如果这些接口返回了用户隐私数据,却被 CDN 缓存,就会造成数据泄露。
2. 缓存键配置错误
缓存键通常与以下因素有关:
- URL;
- Query 参数;
- Cookie;
- Header;
- Host;
- 语言;
- 设备类型。
如果缓存键没有包含必要的用户身份信息,就可能导致不同用户命中同一份缓存。
3. Header 引发的缓存污染
某些应用会根据 Header 返回不同内容,例如:
X-Forwarded-Host
Host
Accept-Language
User-Agent
如果源站基于这些 Header 动态生成响应,而缓存层没有正确区分,就可能产生缓存污染。
4. 防护建议
对于敏感接口,明确设置:
Cache-Control: no-store
或者:
Cache-Control: private, no-cache, no-store, must-revalidate
对于静态资源,可以设置长期缓存:
Cache-Control: public, max-age=31536000, immutable
对于 API,建议默认不缓存,除非明确确认响应不包含用户敏感数据。
六、风险四:WAF 规则误区与绕过风险
Cloudflare WAF 可以阻断很多常见攻击,例如:
- SQL 注入;
- XSS;
- 命令注入;
- 路径穿越;
- 恶意爬虫;
- 已知漏洞利用请求。
但是 WAF 不是应用安全的替代品。
1. WAF 只能过滤“已知特征”
如果业务存在逻辑漏洞,例如:
- 越权访问;
- 支付金额篡改;
- 任意用户资料查看;
- 未授权 API 调用;
- 弱密码登录;
- 验证码绕过;
这些问题通常不是 WAF 能完全解决的。
2. 规则过宽导致漏报
为了避免误拦截,很多企业会将 WAF 设置得非常宽松,甚至对部分路径关闭规则:
/api/*
/upload/*
/admin/*
如果关闭的位置正好是高风险接口,就可能导致攻击流量直接进入源站。
3. 只依赖托管规则不够
建议结合:
- Cloudflare Managed Rules;
- OWASP Core Ruleset;
- 自定义 WAF 规则;
- Rate Limiting;
- Bot Fight Mode;
- Turnstile;
- 日志审计;
- 源站应用安全校验。
七、风险五:SSL/TLS 配置不当
Cloudflare 提供多种 SSL/TLS 模式:
- Off;
- Flexible;
- Full;
- Full Strict。
其中比较容易产生风险的是 Flexible 模式。
1. Flexible 模式风险
Flexible 模式下:
用户 → Cloudflare:HTTPS
Cloudflare → 源站:HTTP
这意味着用户到 Cloudflare 是加密的,但 Cloudflare 到源站之间不是加密的。
如果源站链路经过不可信网络,就可能存在中间人风险。
此外,Flexible 模式还可能导致:
- 重定向循环;
- Cookie Secure 策略混乱;
- 源站误判协议;
- 安全 Header 配置错误。
2. 推荐配置
建议使用:
Full Strict
即:
用户 → Cloudflare:HTTPS
Cloudflare → 源站:HTTPS,并校验证书
源站证书可以使用:
- 公共 CA 证书;
- Cloudflare Origin Certificate。
同时建议开启:
- Always Use HTTPS;
- HSTS;
- TLS 1.2/1.3;
- Authenticated Origin Pulls;
- Minimum TLS Version。
八、风险六:源站未校验 Cloudflare 请求来源
如果源站公网开放,即使域名流量经过 Cloudflare,攻击者也可以直接用源站 IP 访问。
典型问题
源站 Nginx 配置如下:
server {
listen 80;
server_name example.com;
location / {
proxy_pass http://127.0.0.1:3000;
}
}
该配置没有限制访问来源。只要知道源站 IP,任何人都可以访问。
防护方案
应在源站防火墙或 Web 服务器层限制只允许 Cloudflare IP 回源访问。
例如 Nginx 中可以结合 allow 和 deny:
location / {
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;
proxy_pass http://127.0.0.1:3000;
}
注意:Cloudflare IP 段可能更新,应以 Cloudflare 官方文档为准,并定期同步。
更推荐在云安全组、防火墙层面限制源站入口,而不是只依赖 Nginx。
九、风险七:真实客户端 IP 处理错误
网站接入 Cloudflare 后,源站看到的访问 IP 通常是 Cloudflare 节点 IP,而不是用户真实 IP。
Cloudflare 会通过 Header 传递真实客户端 IP,例如:
CF-Connecting-IP: 203.0.113.10
如果源站应用直接信任客户端传入的 Header,就可能产生伪造风险。
错误示例
const ip = req.headers['cf-connecting-ip'] || req.ip;
如果攻击者直接访问源站 IP,就可以伪造:
CF-Connecting-IP: 127.0.0.1
从而绕过基于 IP 的限制。
正确思路
只有在确认请求来自 Cloudflare IP 段时,才信任 CF-Connecting-IP。
伪代码逻辑:
如果 remote_addr 属于 Cloudflare IP 段:
使用 CF-Connecting-IP
否则:
使用 remote_addr
Nginx 中可以使用 real_ip_header 和 set_real_ip_from:
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 Workers 安全风险
Cloudflare Workers 是边缘计算能力,可以在 Cloudflare 节点上运行 JavaScript/TypeScript 逻辑。
它常用于:
- API 网关;
- 请求转发;
- 鉴权;
- A/B 测试;
- 边缘缓存控制;
- Header 改写;
- 图片处理;
- 安全校验。
但 Workers 写得不好,也可能引入安全问题。
1. 开放代理风险
如果 Worker 根据用户传入的 URL 进行 fetch,且没有限制目标地址,就可能变成开放代理。
危险示例:
export default {
async fetch(request) {
const url = new URL(request.url);
const target = url.searchParams.get("url");
return fetch(target);
}
}
这种代码的问题在于:
- 任意用户可以让 Worker 请求任意地址;
- 可能被用于隐藏攻击来源;
- 可能访问内部资源;
- 可能造成流量滥用。
2. 安全版本示例
应限制目标域名白名单:
const ALLOW_HOSTS = new Set([
"api.example.com",
"static.example.com"
]);
export default {
async fetch(request) {
const url = new URL(request.url);
const target = url.searchParams.get("url");
if (!target) {
return new Response("missing url", { status: 400 });
}
let targetUrl;
try {
targetUrl = new URL(target);
} catch {
return new Response("invalid url", { status: 400 });
}
if (targetUrl.protocol !== "https:") {
return new Response("https only", { status: 400 });
}
if (!ALLOW_HOSTS.has(targetUrl.hostname)) {
return new Response("host not allowed", { status: 403 });
}
return fetch(targetUrl.toString(), {
method: "GET",
headers: {
"User-Agent": "Safe-Cloudflare-Worker"
}
});
}
}
十一、本地实验源码:模拟缓存误配置风险
下面给出一个本地 Node.js 示例,用于演示“敏感数据被错误缓存”的风险。
该示例只适合本地运行,帮助理解 CDN 缓存策略为什么需要谨慎配置。
1. 项目结构
cloudflare-security-demo/
├── package.json
├── server.js
└── README.md
2. package.json
{
"name": "cloudflare-security-demo",
"version": "1.0.0",
"description": "Demo for understanding cache misconfiguration risks",
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.18.3"
}
}
3. server.js
const express = require("express");
const app = express();
const port = 3000;
/**
* 模拟用户登录态
* 实际业务中通常来自 Session、JWT 或 Cookie。
*/
function mockAuth(req, res, next) {
const user = req.query.user || "guest";
const users = {
alice: {
id: 1,
name: "Alice",
email: "alice@example.com",
balance: 8800
},
bob: {
id: 2,
name: "Bob",
email: "bob@example.com",
balance: 1200
},
guest: {
id: 0,
name: "Guest",
email: null,
balance: 0
}
};
req.user = users[user] || users.guest;
next();
}
/**
* 错误示例:
* 用户隐私接口却设置了 public cache。
* 如果该响应被 CDN 缓存,可能导致用户信息泄露。
*/
app.get("/bad/profile", mockAuth, (req, res) => {
res.setHeader("Cache-Control", "public, max-age=600");
res.json({
message: "This is a risky cache configuration.",
user: req.user
});
});
/**
* 正确示例:
* 敏感用户数据禁止缓存。
*/
app.get("/good/profile", mockAuth, (req, res) => {
res.setHeader(
"Cache-Control",
"private, no-cache, no-store, must-revalidate"
);
res.setHeader("Pragma", "no-cache");
res.setHeader("Expires", "0");
res.json({
message: "This response should not be cached by shared proxies.",
user: req.user
});
});
/**
* 静态公共数据可以缓存。
*/
app.get("/public/news", (req, res) => {
res.setHeader("Cache-Control", "public, max-age=3600");
res.json({
title: "Security News",
content: "This is public content and can be cached safely."
});
});
app.listen(port, () => {
console.log(`Demo server running at http://localhost:${port}`);
});
4. 运行方式
npm install
npm start
访问示例:
http://localhost:3000/bad/profile?user=alice
http://localhost:3000/bad/profile?user=bob
http://localhost:3000/good/profile?user=alice
http://localhost:3000/good/profile?user=bob
重点观察响应头中的 Cache-Control。
十二、防护检测脚本:检查响应缓存头
下面提供一个简单的 Python 脚本,用于检查指定 URL 的缓存相关 Header。
它适合企业内部对自己资产进行合规检查。
cache_header_check.py
import sys
import requests
SENSITIVE_HINTS = [
"/user",
"/profile",
"/account",
"/order",
"/payment",
"/admin",
"/api"
]
def is_sensitive_url(url: str) -> bool:
lower_url = url.lower()
return any(hint in lower_url for hint in SENSITIVE_HINTS)
def check_cache_header(url: str):
try:
resp = requests.get(url, timeout=10)
except requests.RequestException as e:
print(f"[ERROR] request failed: {e}")
return
cache_control = resp.headers.get("Cache-Control", "")
cdn_cache = resp.headers.get("CF-Cache-Status", "")
content_type = resp.headers.get("Content-Type", "")
print("=" * 80)
print(f"URL: {url}")
print(f"Status Code: {resp.status_code}")
print(f"Content-Type: {content_type}")
print(f"Cache-Control: {cache_control}")
print(f"CF-Cache-Status: {cdn_cache}")
if is_sensitive_url(url):
if "no-store" not in cache_control.lower():
print("[WARN] Sensitive-looking URL does not contain 'no-store'.")
else:
print("[OK] Sensitive-looking URL contains 'no-store'.")
else:
print("[INFO] URL does not match built-in sensitive path hints.")
print("=" * 80)
def main():
if len(sys.argv) < 2:
print("Usage: python cache_header_check.py [url2] ...")
sys.exit(1)
for url in sys.argv[1:]:
check_cache_header(url)
if __name__ == "__main__":
main()
使用方式
pip install requests
python cache_header_check.py https://example.com/api/user/info
该脚本不会进行攻击测试,只读取响应头并给出缓存策略提示。
十三、防护检测脚本:校验是否存在直接源站访问风险
企业可以在内部维护源站 IP 清单,并检查源站是否仍然允许非 Cloudflare 来源直接访问。
下面是一个安全版检测示例,假设你已经拥有合法授权,并且只检测自己的服务器。
origin_access_check.py
import sys
import requests
def check_origin(origin_ip: str, host: str):
url = f"http://{origin_ip}/"
headers = {
"Host": host,
"User-Agent": "Internal-Origin-Access-Check/1.0"
}
try:
resp = requests.get(url, headers=headers, timeout=10)
except requests.RequestException as e:
print(f"[ERROR] {origin_ip} request failed: {e}")
return
print("=" * 80)
print(f"Origin IP: {origin_ip}")
print(f"Host Header: {host}")
print(f"Status Code: {resp.status_code}")
text = resp.text[:120].replace("\n", " ")
if resp.status_code in [200, 301, 302, 403]:
print(f"Preview: {text}")
if resp.status_code == 200:
print("[WARN] Origin may be directly accessible. Consider firewall restrictions.")
elif resp.status_code in [403, 401]:
print("[INFO] Origin returned access control response.")
else:
print("[INFO] Check result requires manual review.")
print("=" * 80)
def main():
if len(sys.argv) != 3:
print("Usage: python origin_access_check.py ")
sys.exit(1)
origin_ip = sys.argv[1]
host = sys.argv[2]
check_origin(origin_ip, host)
if __name__ == "__main__":
main()
使用方式
pip install requests
python origin_access_check.py 192.0.2.10 example.com
说明:
192.0.2.0/24是文档示例网段。请仅检测你拥有授权的源站 IP。
十四、推荐的 Cloudflare 安全配置清单
下面是一份实践清单,适合网站上线前或安全巡检时使用。
1. DNS 与源站
- [ ] 所有 Web 域名启用 Proxied;
- [ ] 删除废弃 DNS 记录;
- [ ] 测试环境不直接暴露公网;
- [ ] 管理后台不使用公开子域名;
- [ ] 源站安全组只允许 Cloudflare IP 访问 80/443;
- [ ] SSH、数据库、Redis 等端口禁止公网访问;
- [ ] 邮件服务器与 Web 源站分离;
- [ ] 定期检查历史 DNS 暴露风险。
2. SSL/TLS
- [ ] 使用 Full Strict 模式;
- [ ] 源站部署有效证书;
- [ ] 开启 Always Use HTTPS;
- [ ] 开启 HSTS;
- [ ] 禁用过旧 TLS 版本;
- [ ] 开启 Authenticated Origin Pulls。
3. WAF
- [ ] 开启 Cloudflare Managed Rules;
- [ ] 开启 OWASP 规则集;
- [ ] 对后台路径设置更严格规则;
- [ ] 对登录接口配置 Rate Limit;
- [ ] 对 API 接口做鉴权;
- [ ] 对上传接口进行文件类型和大小限制;
- [ ] 定期查看 WAF 日志;
- [ ] 避免随意关闭规则。
4. 缓存
- [ ] 敏感接口设置
Cache-Control: no-store; - [ ] 用户页面禁止公共缓存;
- [ ] 静态资源使用版本号或 hash;
- [ ] API 默认不缓存;
- [ ] 避免缓存基于 Cookie 的动态页面;
- [ ] 检查 Page Rules、Cache Rules、Transform Rules;
- [ ] 对缓存命中进行日志审计。
5. Header 安全
建议配置:
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
Content-Security-Policy: default-src 'self'
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: geolocation=(), microphone=(), camera=()
6. 日志与监控
- [ ] 开启 Cloudflare Analytics;
- [ ] 关注异常国家、ASN、路径访问;
- [ ] 记录 WAF 命中日志;
- [ ] 对 403、429、5xx 异常告警;
- [ ] 对登录失败次数告警;
- [ ] 对源站直接访问告警;
- [ ] 将日志接入 SIEM 或集中日志系统。
十五、企业加固方案示例
一个较为安全的 Cloudflare 接入架构如下:
用户
↓
Cloudflare DNS / CDN / WAF / Rate Limit
↓
Authenticated Origin Pulls
↓
云防火墙,只允许 Cloudflare IP
↓
Nginx / API Gateway
↓
业务服务
↓
数据库内网访问
关键点包括:
- 边缘层过滤:使用 WAF、Bot 管理、Rate Limit;
- 传输层加密:Cloudflare 到源站使用 HTTPS 且严格校验证书;
- 源站访问控制:源站不允许公网任意 IP 访问;
- 应用层安全:业务代码自身完成鉴权、输入校验、权限控制;
- 缓存隔离:敏感数据不进入共享缓存;
- 日志追踪:边缘日志与源站日志关联分析;
- 持续巡检:定期检查 DNS、端口、证书、Header、WAF 命中情况。
十六、总结
Cloudflare 能显著提升网站的可用性和安全性,但它不是“接入即安全”的银弹。
多数所谓的“Cloudflare 安全漏洞”,本质上并不是 Cloudflare 平台自身漏洞,而是由以下原因造成:
- 源站 IP 暴露;
- DNS 记录配置错误;
- 灰云解析误用;
- 源站防火墙未限制;
- SSL/TLS 模式选择不当;
- 敏感数据错误缓存;
- WAF 策略过宽;
- Workers 编写不安全;
- 应用自身存在逻辑漏洞。
企业在使用 Cloudflare 时,应从“边缘防护 + 源站加固 + 应用安全 + 持续监控”四个维度建立完整防护体系。
最终目标不是单纯依赖 Cloudflare 拦截攻击,而是让攻击者即使绕过某一层防护,也无法轻易触达核心资产。
安全不是一个开关,而是一套持续演进的工程体系。