上一篇 下一篇 分享链接 返回 返回顶部

别让 Cloudflare 成摆设:源站泄露、缓存误配与自查脚本实战

发布人:慈云数据-客服中心 发布时间:7小时前 阅读量:4

Cloudflare 安全漏洞分析|附源码

说明:本文面向安全研究、架构审计与防御加固场景,重点分析 Cloudflare 使用过程中常见的安全风险、配置漏洞与防护误区。文中“源码”部分提供的是本地可运行的安全检测与演示代码,用于帮助开发者理解风险原理、检查自身资产配置,不包含针对第三方目标的攻击利用代码。


一、前言

Cloudflare 是目前全球使用最广泛的 CDN、DNS、WAF 与边缘安全平台之一。大量网站会将域名解析托管到 Cloudflare,并借助其提供的 DDoS 防护、反向代理、缓存、TLS、访问控制、Bot 管理、Web Application Firewall 等能力来提升网站性能与安全性。

然而,在实际安全评估中,我们经常发现一个现象:很多企业或个人站点“接入了 Cloudflare”,但并不等于“已经安全”。Cloudflare 本身作为成熟平台,安全能力非常强,但最终防护效果高度依赖于使用者的配置方式、源站暴露情况、DNS 管理习惯、业务访问策略以及后端应用自身安全性。

换句话说,Cloudflare 更像是一层强大的安全边界,但如果边界配置不当,或者源站绕过了这层边界,攻击者依然可能直接访问真实服务器,从而绕过 CDN/WAF 的防护。

本文将从以下几个方面展开:

  1. Cloudflare 的基本防护模型;
  2. 常见安全风险与漏洞类型;
  3. 源站 IP 泄露问题分析;
  4. WAF 与缓存配置误区;
  5. SSL/TLS 配置风险;
  6. 访问控制与 Zero Trust 使用建议;
  7. 安全检查脚本源码示例;
  8. 加固建议与安全清单。

二、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.comorigin.example.comdev.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 安全建议

建议配置如下:

  1. SSL/TLS 模式选择 Full Strict
  2. 源站部署有效证书;
  3. 开启 Always Use HTTPS;
  4. 开启 HTTP Strict Transport Security;
  5. 最低 TLS 版本建议 TLS 1.2 或更高;
  6. 关闭过时加密协议;
  7. 对敏感业务启用 mTLS 或 Cloudflare Access;
  8. 使用 Origin Certificate 时注意证书有效期管理。

HSTS 示例:

Strict-Transport-Security: max-age=31536000; includeSubDomains; preload

但启用 includeSubDomainspreload 前必须确认所有子域均支持 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 架构应该满足以下条件:

  1. 域名请求必须经过 Cloudflare;
  2. 源站不能被公网直接访问;
  3. WAF、Bot、Rate Limiting 需要按业务定制;
  4. 动态内容缓存必须谨慎;
  5. TLS 应实现端到端加密;
  6. 后台与敏感接口应使用 Zero Trust 或 Access 保护;
  7. 应定期审计 DNS、证书、日志与配置变化。

从防御视角看,Cloudflare 的价值不仅在于“隐藏源站”或“抵御攻击”,更在于它提供了一套边缘安全控制面。只有将 Cloudflare 与源站防火墙、应用安全编码、身份认证、日志监控、漏洞管理结合起来,才能形成真正有效的纵深防御体系。

本文提供的检测脚本可以作为日常安全巡检的起点,用于发现基础配置问题。对于生产环境,还应结合自动化资产扫描、Cloudflare API、SIEM 日志分析和人工安全审计,持续提升整体安全水位。

目录结构
全文