Cloudflare API 限流与源站防护配置总结
1. 背景
服务器安全组已经关闭了公网 80 和 443 入站端口,仅保留 SSH 白名单访问。
但是应用日志中仍然出现了大量请求,例如:
{
"method": "GET",
"path": "/api/app/getserviceinfo",
"status": 404,
"clientIp": "172.x.x.x"
}
这些请求看起来像自动化扫描器在探测接口路径。
经过排查,发现请求并不是直接通过服务器公网 80/443 端口进入,而是可能通过以下链路进入:
外部请求
-> Cloudflare
-> Cloudflare Tunnel / 反向代理
-> Docker 网络
-> 应用服务
因此,即使云服务器安全组关闭了 80/443,只要 Cloudflare Tunnel 或代理入口仍然存在,外部请求仍可能通过域名进入应用。
2. 关键判断
应用日志中的客户端 IP 类似:
172.x.x.x
这类地址通常是 Docker 内部网络地址,不是攻击者真实公网 IP。
说明请求大概率经过了:
Cloudflare / Traefik / Dokploy / Docker 网关
应用看到的是内部网关 IP,而不是用户真实 IP。
建议应用日志增加以下字段,方便后续定位真实来源:
Host
CF-Connecting-IP
X-Forwarded-For
X-Real-IP
User-Agent
Path
Method
Gin 示例:
log.Printf(
"ClientIP=%s Host=%s CF=%s XFF=%s RealIP=%s UA=%s Path=%s Method=%s",
c.ClientIP(),
c.Request.Host,
c.GetHeader("CF-Connecting-IP"),
c.GetHeader("X-Forwarded-For"),
c.GetHeader("X-Real-IP"),
c.GetHeader("User-Agent"),
c.Request.URL.Path,
c.Request.Method,
)
3. 攻击者如何知道 IP 或域名
常见来源包括:
3.1 域名 DNS 暴露
只要域名或子域名曾经解析到服务器 IP,就可能被记录在被动 DNS 数据库中。
例如:
api.example.com -> 源站 IP
admin.example.com -> 源站 IP
即使后续删除或切换到 Cloudflare,也可能存在历史记录。
3.2 证书透明日志
只要给子域名申请过 HTTPS 证书,域名可能会出现在公开的证书透明日志中。
扫描器会批量监听新证书并自动探测相关域名。
3.3 云服务器 IP 段扫描
扫描器不一定知道域名,也可能直接扫描云厂商 IP 段。
常见扫描端口包括:
80
443
22
3000
8080
5432
6379
3.4 前端代码暴露 API 地址
如果前端代码中包含:
const API_BASE_URL = "https://api.example.com"
用户和扫描器都可以通过浏览器源码或抓包看到 API 域名。
API 域名本身不应依赖隐藏来保证安全。
4. Cloudflare 为什么一开始没有拦截
Cloudflare 默认不会因为“同一秒出现请求”就一定拦截。
未拦截的常见原因:
1. 未配置 Rate Limiting 规则;
2. 请求只是普通 GET/HEAD 探测,没有明显攻击特征;
3. 默认 WAF 主要拦截 SQL 注入、XSS、路径穿越等攻击载荷;
4. Bot 防护不是万能的;
5. 请求频率没有超过已配置的限流阈值。
例如配置为:
30 次 / 10 秒
但脚本是:
1 秒 1 次
那么 10 秒内只有约 10 次请求,没有超过阈值,因此不会触发限流。
5. Cloudflare API 限流配置
5.1 配置入口
进入 Cloudflare 控制台:
Websites
-> 选择站点
-> Security
-> WAF
-> Rate limiting rules
-> Create rule
或新版入口:
Security
-> Security rules
-> Rate limiting rules
-> Create rule
6. API 限流规则
规则名称
api限速
匹配条件
建议同时限制 Host 和 API 路径,避免影响其他子域名。
表达式示例:
(http.host eq "api.example.com" and http.request.uri.path wildcard r"/api/*")
含义:
只限制 api.example.com 这个 API 域名
并且只限制 /api/* 开头的接口
相同特征
IP
表示按单个客户端 IP 计数。
阈值
生产环境建议:
30 次 / 10 秒
或更严格:
20 次 / 10 秒
测试规则是否生效时,可以临时设置为:
5 次 / 10 秒
动作
测试阶段:
Managed Challenge
确认没有误伤后,可以改为:
Block
持续时间
10 分钟
7. 推荐配置
普通 API 限流
规则名称:
api限速
匹配条件:
Host = api.example.com
AND URI 路径 通配符 /api/*
表达式:
(http.host eq "api.example.com" and http.request.uri.path wildcard r"/api/*")
相同特征:
IP
阈值:
30 次 / 10 秒
动作:
Managed Challenge
持续时间:
10 分钟
8. 测试配置是否生效
Linux / macOS:
for i in {1..20}; do
curl -I https://api.example.com/api/test
done
Windows PowerShell:
1..20 | ForEach-Object {
curl.exe -I https://api.example.com/api/test
}
测试时建议临时设置:
5 次 / 10 秒
如果规则生效,前几次请求会正常到达应用,超过阈值后会被 Cloudflare 拦截。
注意:
Rate Limiting 不是第一下就拦截;
它会先放行并计数;
超过阈值后才开始执行 Challenge 或 Block。
9. HEAD 请求问题
测试日志中可能出现:
Method: HEAD
Path: /api/test
Status: 404
如果限流规则只匹配 URI 路径,HEAD 请求也会被统计。
但如果规则额外限制了:
Method = GET
那么 HEAD 请求不会命中规则。
因此测试阶段建议不要限制 Method。
10. 后台域名防护建议
后台管理域名不建议只靠 Rate Limiting。
推荐使用:
Cloudflare Access
保护后台域名:
admin.example.com
deploy.example.com
dokploy.example.com
推荐策略:
后台管理域名:
只允许指定邮箱登录访问
CI/CD 部署入口:
使用 Cloudflare Access Service Token
这样可以避免后台直接暴露给公网扫描器。
11. CI/CD 与 Cloudflare Access
如果 CI/CD 需要访问受 Cloudflare Access 保护的部署接口,需要配置 Service Token。
请求时携带:
CF-Access-Client-Id
CF-Access-Client-Secret
示例:
curl -X POST "https://deploy.example.com/api/deploy" \
-H "CF-Access-Client-Id: $CF_ACCESS_CLIENT_ID" \
-H "CF-Access-Client-Secret: $CF_ACCESS_CLIENT_SECRET" \
-H "Authorization: Bearer $DEPLOY_TOKEN"
推荐保护方式:
Cloudflare Access Service Token
+
应用自身 API Token
不要直接把整个后台域名设置为 Bypass。
12. 额外防护建议
12.1 删除无用 DNS 记录
不再使用的子域名应删除 DNS 记录或 Tunnel Public Hostname。
12.2 API 接口增加认证
不要只依赖 Cloudflare,后端接口仍然需要:
登录认证
权限校验
Token 校验
参数校验
12.3 登录/验证码接口单独限流
登录、注册、发送验证码接口建议更严格:
5 次 / 1 分钟
例如:
/api/user/login
/api/user/register
/api/user/send-code
12.4 常见扫描路径直接 Block
可以在 Cloudflare WAF Custom Rules 中直接拦截:
/.env
/wp-
/phpmyadmin
/api/app/getserviceinfo
示例表达式:
(
http.request.uri.path contains "/.env"
or http.request.uri.path contains "/wp-"
or http.request.uri.path contains "/phpmyadmin"
or http.request.uri.path contains "/api/app/getserviceinfo"
)
动作:
Block
13. 最终结论
本次问题的核心原因是:
服务器关闭 80/443 只能阻止外部直接访问源站端口;
如果仍然存在 Cloudflare Tunnel、反向代理或域名入口,请求仍然可以进入应用;
Cloudflare 默认不会拦截所有普通路径扫描;
需要手动配置 Rate Limiting、WAF Custom Rules 和 Access。
本次已验证:
Cloudflare Rate Limiting 规则有效;
当请求频率超过设置阈值后,会触发 Cloudflare 拦截;
应用日志中不再持续收到超过阈值后的请求。
推荐长期配置:
API 域名:
Rate Limiting + WAF Custom Rules + 后端认证
后台域名:
Cloudflare Access + 指定邮箱访问
CI/CD:
Cloudflare Access Service Token + 应用部署 Token
源站服务器:
安全组只开放必要端口,SSH 仅允许白名单 IP